您的位置:首页 > 移动开发 > Android开发

APK安装时原来的apk安装信息没有被清掉产生安装垃圾问题的解决办法

2016-12-16 17:39 417 查看
问题描述:

下载三个apk(http://pan.baidu.com/s/1geS25r1):

在android5.0 及以上平台:
1、将331.apk 替换掉系统内置的/system/vendor/app/SkyAppStore/SkyAppStore.apk ,并 rm -rf /data/data/com.tianci.appstore。rm -rf /data/app/com.tianci.appstore-xxx。 然后重启电视
2、pm install -r /mnt/usb/sda1/523.apk,恢复出厂设置:保留应用。问题1:
3、再次pm install -r /mnt/usb/sda1/622.apk,。 问题2:


问题:

1、电视重启后,通过pm path com.tianci.appstore发现,系统用的是system下的,而不是data下的
2、再次安装新的后,pm path com.tianci.appstore 使用的是data/app/com.tianci.appstore-2。而com.tianci.appstore-1还在。


任务:

1、查android源码,找出问题1/2的原因
2、提供解决方案:如何避免com.tianci.appstore-1垃圾的产生。


问题1产生的原因:

系统恢复出厂设置时会删除packages.xml和packages.list文件,这两个文件中记录的是系统已安装的应用信息,包括用户应用和系统应用,系统再次开机时,回会先扫描system下的app安装,之后才会扫描data下面的app进行安装,其中扫描安装过程中会调用一下两个判断(位于PackageManagerService.java):


if (mPackages.containsKey(pkg.packageName) ||  mSharedLibraries.containsKey(pkg.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,"Application package " +pkg.packageName+ " already installed. Skipping duplicate.");
}


这个判断是检查该apk是否已被安装过,若已被安装过得apk包含这个apk信息,则直接抛出异常不再重复安装,所以对于系统自带的apk,及时data下有也不会重新安装


if (!pkg.applicationInfo.getCodePath().equals(known.codePathString) || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {
    throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,"Application package " +            pkg.packageName + " found at " + pkg.applicationInfo.getCodePath() + " but expected at " + known.codePathString +     "; ignoring.");
}


这个判断是检查当前要安装的apk路径与已被安装的apk的配置信息是否一致,若不一致则抛出异常,不再安装次apk,由于系统自带的apk的安装路径是指向system目录的,所以即使data下有该apk也不会更新apk的安装信息。
综上:系统恢复出厂设置后,及时data下也有系统自带apk的安装信息,也还是会使用system下的apk,而不会使用data下的apk。


问题2产生的原因:

private File getNextCodePath(String packageName) {
  int suffix = 1;
  File result;
  do {
    result = new File(mAppInstallDir, packageName + "-" + suffix);
    suffix++;
  } while (result.exists());
  return result;
}


pm install -r /mnt/usb/sda1/523.apk会调用以上函数来产生自己的安装文件夹,由次函数可以看出:如果检测到data/app下如果有此app的安装文件夹,则自动将后缀加1(suffix++;),pm install -r /mnt/usb/sda1/523.apk后会在data/app下产生com.tianci.appstore-1的文件夹,恢复出厂设置后,由于系统带有appstore的apk,所以系统会安装自带的apk,而此时data/app下的appstore的安装文件并没有被删掉,此时pm path com.tianci.appstore查看系统使用的app路劲会得到:/system/vendor/app/SkyAppStore/SkyAppStore.apk,即是用的系统apk,当再次pm install -r /mnt/usb/sda1/622.apk时,系统根据packages.xml只检测到了系统自带的apk,没有检测到之前用户自己安装过SkyAppStore.apk,所以再次安装的时候只会卸载掉系统apk(更新packages.xml,而不是把/system/vendor/app/SkyAppStore/SkyAppStore.apk删掉),然后调用getNextCodePath函数在data/app下产生自己的文件夹,此时就产生了com.tianci.appstore-1垃圾。


问题2解决方式一(验证通过):

pm install -r /mnt/usb/sda1/622.apk时,若data/app下已存在该包名的文件夹则直接删掉,修改getNextCodePath函数:


private File getNextCodePath(String packageName) {
int suffix = 1;
File result = new File(mAppInstallDir, packageName + "-" + suffix);
for(;result.exists();)
{
if(result.isDirectory())
{
FileUtils.deleteContents(result);
}
result.delete();
suffix++;
result = new File(mAppInstallDir, packageName + "-" + suffix);
}
result = new File(mAppInstallDir, packageName + "-" + 1);
return result;
}


问题2解决方式二(验证通过):

回复出厂设置时,允许apk重复安装,等同于优先使用data下的apk,,注释掉两个判断即可:


/*
if (mPackages.containsKey(pkg.packageName) || mSharedLibraries.containsKey(pkg.packageName)) { throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,"Application package " +pkg.packageName+ " already installed. Skipping duplicate."); }*/

/*
if (!pkg.applicationInfo.getCodePath().equals(known.codePathString) || !pkg.applicationInfo.getResourcePath().equals(known.resourcePathString)) {     throw new PackageManagerException(INSTALL_FAILED_PACKAGE_CHANGED,"Application package " +            pkg.packageName + " found at " + pkg.applicationInfo.getCodePath() + " but expected at " + known.codePathString +     "; ignoring."); }*/


潜在的问题:1、系统恢复出厂设置的原则是将系统回复到出厂状态,若使用此修改,相当于系统没有恢复到最原始的状态


      2、若用户已安装过系统apk,然后回复出厂设置,再卸载该apk后,系统自带的该apk也不可使用,因为重复安装会直接删除system下的apk安装信息,而不会将其修改为update-package,此时,只有重启电视,系统才会重新安装system下的apk,然后可以正常使用(尝试继续研究解决办法)

问题2解决方式三(验证通过):

系统第一次开机时直接删除安装失败的软件包,mRestoredSettings是判断是否为第一次开机的标志。


// Delete invalid userdata apps
if (((parseFlags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
  e.error == PackageManager.INSTALL_FAILED_INVALID_APK) || !mRestoredSettings) {
  logCriticalInfo(Log.WARN, "Deleting invalid package at " + file);
  if (file.isDirectory()) {
    FileUtils.deleteContents(file);
  }
  file.delete();
}


潜在问题:若用户在升级到该系统版本前执行操作:pm install -r /mnt/usb/sda1/622.apk,然后恢复出厂设置,此时data/app下存在com.tianci.appstore-1,pm path com.tianci.appstore可以看到系统用的是system下的apk,这是系统升级到该版本,然后pm install -r /mnt/usb/sda1/622.apk会在data/app下产生com.tianci.appstore-2文件夹,需要再恢复一次出厂设置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐