主要运用到的类有
PackageManager
ActivityManager
ApplicationInfo
RunningServiceInfo
Method
还有两个android.pm下的源文件用于生成桩,IPackageStatsObserver.java 和 IPackageDataObserver.java,由名字可以看出,他们是跟包的状态和大小有关的,在网上找到这两个文件的源码后,把他们放在工程src目录下的android.pm包下,自己建包。
首先要获得系统中已经装了的apk,apk分为两类第一是系统的apk,第二是第三方的apk,所以在获取apk时可以指定一个过滤器,见如下代码:
- private List<AppInfo> queryFilterAppInfo(int filter) {
-
- List<ApplicationInfo> listAppcations = pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
- Collections.sort(listAppcations,new ApplicationInfo.DisplayNameComparator(pm));
- List<AppInfo> appInfos = new ArrayList<AppInfo>();
-
- switch (filter) {
- case FILTER_ALL_APP:
- appInfos.clear();
- for (ApplicationInfo app : listAppcations) {
- if (app.packageName.equals("com.android.appmanager")) {
- continue;
- }
- appInfos.add(getAppInfo(app));
- }
- return appInfos;
- case FILTER_SYSTEM_APP:
- appInfos.clear();
- for (ApplicationInfo app : listAppcations) {
- if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
- if (app.packageName.equals("com.android.appmanager"<span style="font-family:Arial, Helvetica, sans-serif;">)</span>
- continue;
- }
- appInfos.add(getAppInfo(app));
- }
- }
- return appInfos;
- case FILTER_THIRD_APP:
- appInfos.clear();
- for (ApplicationInfo app : listAppcations) {
-
- if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
- if (app.packageName.equals("com.android.appmanager"))
- continue;
- }
- appInfos.add(getAppInfo(app));
- }
-
- else if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- if (app.packageName.equals("geeya.android.appmanage")) {
- continue;
- }
- appInfos.add(getAppInfo(app));
- }
- }
- break;
- default:
- return null;
- }
- return appInfos;
- }
AppInfo是我自己定义的一个类,里面包含了应用程序的包名、数据区大小、代码区大小、等等一些属性。
好,现在我们来获取app包的数据区大小、缓存区大小、代码区大小,这里要用反射的机制去获取PackageManager类的隐藏方法getPackageSizeInfo(),这个方法的具体实现是通过回调函数来实现的,这里要用到IPackageStatsObserver这个类生成的桩。
- public class PkgSizeObserver extends IPackageStatsObserver.Stub {
-
- @Override
- public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {
- long cachesize;
- long datasize;
- long codesize;
- long totalsize;
-
- synchronized (Integer.class) {
- cachesize = pStats.cacheSize;
- datasize = pStats.dataSize;
- codesize = pStats.codeSize;
- totalsize = cachesize + datasize + codesize;
- Message msg = mHandler.obtainMessage();
-
- msg.what = MSG_SIZE_CHANGE;
- Bundle bundle = new Bundle();
- bundle.putLong("cachesize", cachesize);
- bundle.putLong("datasize", datasize);
- bundle.putLong("codesize", codesize);
- bundle.putLong("totalsize", totalsize);
-
- bundle.putString("packageName", pStats.packageName);
- msg.obj = bundle;
- mHandler.sendMessage(msg);
- }
- }
- }
-
-
-
- public void queryPacakgeSize(String pkgName) throws Exception {
- if (pkgName != null) {
-
- PackageManager pm = getPackageManager();
- try {
-
- Method getPackageSizeInfo = pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,
- IPackageStatsObserver.class);
- getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
- } catch (Exception ex) {
-
- ex.printStackTrace();
- throw ex;
- }
- }
- }
或得到app的大小数据后,封装成消息发送出去,这是最好的方法!!
这里也介绍一个将long型数据转换成文件大小格式的数据。
- private String formateFileSize(long size) {
- return Formatter.formatFileSize(MainActivity.this, size);
- }
好,现在我们来清除用户数据,这里要用到之前下载的那个文件IPackageDataObserver,跟获取app大小一样的,通过回调来实现。
-
- class ClearUserDataObserver extends IPackageDataObserver.Stub {
- public void onRemoveCompleted(final String packageName,final boolean succeeded) {
- final Message msg = mHandler.obtainMessage();
- if (succeeded) {
- msg.what = CLEAR_USER_DATA;
- } else {
- msg.what = NOT_CLEAR_USER_DATA;
- }
- mHandler2.sendMessage(msg);
- }
- }
- public void clearAppUserData(String pkgname){
-
- pm.clearApplicationUserData(pkgname, new ClearUserDataObserver());
- }
好,现在到卸载程序的时候了,看代码
-
- ublic void unInstallApp(String pkgname) {
- Log.e("unInstallApp(String pkgname)","pkgname is"+ pkgname);
- Intent intent = new Intent();
- intent.setAction("android.intent.action.DELETE.HIDE");
- Uri packageURI = Uri.parse("package:" + pkgname);
- intent.setData(packageURI);
- startActivity(intent);
关于apk的管理就差不多了,现在来看看正在运行的服务的管理
首先,获取正在运行的服务:
这里我的RunningInfo是我自己定义的一个类,主要服务的一些属性,比如包名、uid、pid等等那些
- public List<RunningInfo> getRunningService() {
- List<RunningServiceInfo> runServiceList = am.getRunningServices(30);
- List<RunningInfo> Services_List = new ArrayList<RunningInfo>();
- Log.e("getRunningService.size = ",
- new Integer(runServiceList.size()).toString());
- String pkgname = "";
- ApplicationInfo appByPkgName = null;
- for (RunningServiceInfo info : runServiceList) {
- pkgname = info.service.getPackageName();
-
-
-
- if (pkgname.equals("com.android.appmanager") ) {
- continue;
- }
- try {
- appByPkgName = pm.getApplicationInfo(pkgname,
- PackageManager.GET_UNINSTALLED_PACKAGES);
-
- } catch (NameNotFoundException e) {
-
- e.printStackTrace();
- }
-
- Services_List.add(getRunningInfo(appByPkgName));
- }
-
- Set<RunningInfo> set = new HashSet<RunningInfo>();
- for (RunningInfo x : Services_List) {
- set.add(x);
- }
- for (RunningInfo y : set) {
- Services_List.add(y);
- }
- return Services_List;
- }
好,获取到了正在运行的服务之后,就可以随意停止服务了,停止服务的代码是:
-
- ublic boolean stopApp(String pkgname) {
- boolean flag = false;
- ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
- try {
- Method forceStopPackage;
- forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage", String.class);
- forceStopPackage.setAccessible(true);
- forceStopPackage.invoke(am, pkgname);
- flag = true;
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- flag = false;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- flag = false;
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- flag = false;
- } catch (SecurityException e) {
- e.printStackTrace();
- flag = false;
- } catch (NoSuchMethodException e) {
- e.printStackTrace();
- flag = false;
- }
- return flag;
同样也是用反射的机制来得到隐藏类。
到这里,应用程序管理的功能就差不多了,剩下就只是界面上的事情和程序的处理流程上的事情,应该还好!