Android 4.4 安装INSTALL_FAILED_SHARED_USER_INCOMPATIBLE后原APK无法使用问题分析

背景:

记录最近在项目中遇到的一个问题,先说现象:
/system/app/下原本有一个可以正常使用的APK,APK本想下发自升级,APK存在问题无法安装成功,但奇怪的是,原本/system/app/下正常的APK也无法使用了。
从pm命令及ps命令都看到/system/app/下的APK没有运行。

调试:

1、把问题APK拿到后测试,pm installI -r xxx.apk 手动安装,返回
INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,这个错误是因为APK设置了UIDandroid:sharedUserId="android.uid.system",但没有用系统签名导致,这是APK方的失误。
安装报错后重启,就复现问题,pm -lf找不到原本/system/app/下的apk了。

2、使用dumpsys命令调试
dumpsys package com.xxx.xxx
安装前:
Android 4.4 安装INSTALL_FAILED_SHARED_USER_INCOMPATIBLE后原APK无法使用问题分析_第1张图片
安装后:
Android 4.4 安装INSTALL_FAILED_SHARED_USER_INCOMPATIBLE后原APK无法使用问题分析_第2张图片
可以看到有两个异常:

  • APK 状态installed=true,但enable=2, 2的状态是禁止状态,就如同 pm disable
  • APK的路径仍然使用的是/system/app/下的路径,而在下面可以看到,/system/app/下的APK是被隐藏了

分析:

1、
简单列下PMS安装流程。
安装一个APK的流程可以简单分为拷贝->装载这两部分。
装载部分的核心函数:
installPackageLI
->>因为我们是APK更新,所以是replace
replacePackageLI
->>更新系统APK
replaceSystemPackageLI
->>
scanPackageLI
->>
verifySignaturesLP

而INSTALL_FAILED_SHARED_USER_INCOMPATIBLE的报错则是出现在签名校验部分,即verifySignaturesLP函数中。

2、
跟进代码,replaceSystemPackageLI中对新APK校验之前,会判断是否应该禁止原来的system app。
在开始会先disableSystemPackageLPw禁止老的system app,对新app进行校验,这样当高版本APK安装完成后,则会使用/data/app/路径下的APK,/system/app/下的则被隐藏了。

scanPackageLI:
......省略

 synchronized (mPackages) {
     if (!mSettings.disableSystemPackageLPw(packageName) && deletedPackage != null) {
          // We didn't need to disable the .apk as a current system package,
          // which means we are replacing another update that is already
          // installed.  We need to make sure to delete the older one's .apk.
          res.removedInfo.args = createInstallArgs(0,
                  deletedPackage.applicationInfo.sourceDir,
                  deletedPackage.applicationInfo.publicSourceDir,
                  deletedPackage.applicationInfo.nativeLibraryDir);
      } else {
          res.removedInfo.args = null;
      }
  }
  
  // Successfully disabled the old package. Now proceed with re-installation
  mLastScanError = PackageManager.INSTALL_SUCCEEDED;
  pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
  newPackage = scanPackageLI(pkg, parseFlags, scanMode, 0, user);
  if (newPackage == null) {
      Slog.w(TAG, "Package couldn't be installed in " + pkg.mPath);
      if ((res.returnCode=mLastScanError) == PackageManager.INSTALL_SUCCEEDED) {
          res.returnCode = PackageManager.INSTALL_FAILED_INVALID_APK;
      }
  } else {
      if (newPackage.mExtras != null) {
          final PackageSetting newPkgSetting = (PackageSetting)newPackage.mExtras;
          newPkgSetting.firstInstallTime = oldPkgSetting.firstInstallTime;
          newPkgSetting.lastUpdateTime = System.currentTimeMillis();
      }
      updateSettingsLI(newPackage, installerPackageName, allUsers, perUserInstalled, res);
      updatedSettings = true;
  }

  if (res.returnCode != PackageManager.INSTALL_SUCCEEDED) {
      // Re installation failed. Restore old information
      // Remove new pkg information
      if (newPackage != null) {
          removeInstalledPackageLI(newPackage, true);
      }
      // Add back the old system package
      scanPackageLI(oldPkg, parseFlags, SCAN_MONITOR | SCAN_UPDATE_SIGNATURE, 0, user);
      // Restore the old system information in Settings
      synchronized(mPackages) {
          if (updatedSettings) {
              mSettings.enableSystemPackageLPw(packageName);
              mSettings.setInstallerPackageName(packageName,
                      oldPkgSetting.installerPackageName);
          }
          mSettings.writeLPr();
      }
  }

3、
从上面代码可以看出,如果verifySignaturesLP校验失败,最终scanPackageLI会返回null,因为更新失败,所以不会走到updateSettingsLI更新APK的路径,状态等。
而失败的情况下,因为updatedSettings为false,所以也不会重新把/system/app/的APK给重新解放出来,这就导致了重启后,原本/system/app/下的APK也无法使用了。

4、
因为对PMS没有太深入的研究,不太能理解为什么Android 4.4上会这么写,但问题确实是存在的,查看更高版本的Android系统源码,这部分已经被修改了,verifySignaturesLP被提前,校验失败则不需要更新APK信息。

解决:

尝试修改,将INSTALL_FAILED_SHARED_USER_INCOMPATIBLE错误的updatedSettings设置为true。
replaceSystemPackageLI中修改如下代码,暂时测试正常,仍需要进一步排查影响,毕竟不清楚Android 4.4上这样写的原因。
Android 4.4 安装INSTALL_FAILED_SHARED_USER_INCOMPATIBLE后原APK无法使用问题分析_第3张图片

你可能感兴趣的:(Android)