Fota升级之后无法开机

Fota升级之后无法开机

分析

Crash的地方:

08-03 10:42:29.051   723   723 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: main
08-03 10:42:29.051 723 723 E AndroidRuntime: java.lang.NullPointerException: Attempt to read from field 'java.lang.String com.android.server.pm.PackageSettingBase.name' on a null object reference
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.scanPackageInternalLI(PackageManagerService.java:9710)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.scanPackageLI(PackageManagerService.java:9451)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.scanDirLI(PackageManagerService.java:9265)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.scanDirTracedLI(PackageManagerService.java:9212)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.<init>(PackageManagerService.java:2656)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.pm.PackageManagerService.main(PackageManagerService.java:2338)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.SystemServer.startBootstrapServices(SystemServer.java:601)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.SystemServer.run(SystemServer.java:399)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.server.SystemServer.main(SystemServer.java:277)
08-03 10:42:29.051 723 723 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
08-03 10:42:29.051 723 723 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:787)
08-03 10:42:29.053 723 723 E AndroidRuntime: Error reporting crash
08-03 10:42:29.053 723 723 E AndroidRuntime: java.lang.NullPointerException: Attempt to invoke interface method 'void android.app.IActivityManager.handleApplicationCrash(android.os.IBinder, android.app.ApplicationErrorReport$ParcelableCrashInfo)' on a null object reference
08-03 10:42:29.053 723 723 E AndroidRuntime: at com.android.internal.os.RuntimeInit$KillApplicationHandler.uncaughtException(RuntimeInit.java:116)
08-03 10:42:29.053 723 723 E AndroidRuntime: at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1068)
08-03 10:42:29.053 723 723 E AndroidRuntime: at java.lang.ThreadGroup.uncaughtException(ThreadGroup.java:1063)
08-03 10:42:29.053 723 723 E AndroidRuntime: at java.lang.Thread.dispatchUncaughtException(Thread.java:1955)

直接原因是ps空指针造成的.

发现是如下两个地方都返回了空.

if (pkg.mOriginalPackages != null && pkg.mOriginalPackages.contains(oldName)) {
// This package has been renamed to its original name. Let's
// use that.
ps = mSettings.getPackageLPr(oldName);
}
// If there was no original package, see one for the real package name.
if (ps == null) {
ps = mSettings.getPackageLPr(pkg.packageName);
}

查看代码发现,mSettings 是PMS初始化的时候一起初始化的,并且会维护所有包的信息,读写文件:

public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());

if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}

mContext = context;

mPermissionReviewRequired = context.getResources().getBoolean(
R.bool.config_permissionReviewRequired);

mFactoryTest = factoryTest;
mOnlyCore = onlyCore;
/* niuwenchao modify 20180104 for 8909go preloadapp start */
mPreInstallDir = new File("/system/preloadapp");
/* niuwenchao modify 20180104 for 8909go preloadapp end */
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
PS: 不排除是"niuwenchao" 修改,或者是suyibang最近打的security patch引起的.(没有回退代码做压力测试,此问题也比较难复现)。

下面是自己加的LOG

05-31 02:05:29.416  3563  3563 W PackageSettings: mSystemDir/data/system, mSettingsFilename = /data/system/packages.xml,mBackupSettingsFilename = /data/system/packages-backup.xml,mPackageListFilename = /data/system/packages.list,mKernelMappingFilename =/config/sdcardfs,mStoppedPackagesFilename = /data/system/packages-stopped.xml,mBackupStoppedPackagesFilename = /data/system/packages-stopped-backup.xml

下载相应的PMS Settings使用的文件

adb pull /data/system/packages.xml
adb pull /data/system/packages-backup.xml
adb pull /data/system/packages-stopped.xml
adb pull /data/system/packages-stopped-backup.xml
adb pull /data/system/packages.list

在 packages.xml 文件中,只有升级记录:

<updated-package name="com.google.android.gms" codePath="/system/priv-app/GmsCore" ft="1636e1ba6c0" it="1636e1ba6c0" ut="1636e1ba6c0" version="12529018" nativeLibraryPath="/system/priv-app/GmsCore/lib" primaryCpuAbi="armeabi-v7a" sharedUserId="10019" />

没有正常的,如下面的这种已经安装的记录:

<package name="com.android.providers.downloads.ui" codePath="/system/app/DownloadProviderUi" nativeLibraryPath="/system/app/DownloadProviderUi/lib" publicFlags="944291397" privateFlags="0" ft="1648fe85388" it="1636e1b9ef0" ut="1648fe85388" version="27" sharedUserId="10013" isOrphaned="true">

/data/system/packages.xml 里面没有GMS的相关节点.这里原因未知,可以暂时假设是某个流程没有走完,导致文件里面的内容未彻底修改完成.

packages.xml 对应的是 mSettingsFilename 变量.

尝试不修改代码解决

导出/data/system/packages.xml文件.

删除以下下内容:

<updated-package name="com.google.android.gms" codePath="/system/priv-app/GmsCore" ft="1636e1ba6c0" it="1636e1ba6c0" ut="1636e1ba6c0" version="12529018" nativeLibraryPath="/system/priv-app/GmsCore/lib" primaryCpuAbi="armeabi-v7a" sharedUserId="10019" />

push回手机.

手机可以正常启动.

相关节点会重新生成,这说明问题的关键点在/data/system/packages.xml的维护当中。

解决方案1:

if (isUpdatedSystemPkg && !isUpdatedPkgBetter && ps != null) {//jackywei
// Set CPU Abis to application info.
if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
} else {
pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
}

if(ps != null){
throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
+ scanFile + " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
} else {
throw new PackageManagerException(Log.WARN, "Package " + " at "
+ scanFile + " ignored: updated version "
+ " better than this " + pkg.mVersionCode);
}
}

手机可以正常开机,但是开机之后手机会提示GMS包没有安装,且依赖GMS包的相关应用无法启动。(Fail).
而且,/data/system/packages.xml 文件中GMS有关的节点不会更新.

解决方案2:

if (isUpdatedSystemPkg && !isUpdatedPkgBetter && ps != null) {//jackywei
// Set CPU Abis to application info.
if ((scanFlags & SCAN_FIRST_BOOT_OR_UPGRADE) != 0) {
final String cpuAbiOverride = deriveAbiOverride(pkg.cpuAbiOverride, updatedPkg);
derivePackageAbi(pkg, scanFile, cpuAbiOverride, false, mAppLib32InstallDir);
} else {
pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
}
throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
+ scanFile + " ignored: updated version " + ps.versionCode
+ " better than this " + pkg.mVersionCode);
}

这样修改之后,PMS会把GMS当成新包解析,并且删除/data/system/packages.xml里面的

<updated-package name="com.google.android.gms" codePath="/system/priv-app/GmsCore" ft="1636e1ba6c0" it="1636e1ba6c0" ut="1636e1ba6c0" version="12529018" nativeLibraryPath="/system/priv-app/GmsCore/lib" primaryCpuAbi="armeabi-v7a" sharedUserId="10019" />

并且,测试GMS包和相关应用都能正常使用。

目前来看,这样是合理与安全的。

涉及到的代码.

两个文件,大概30000行左右的代码.

frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
frameworks/base/services/core/java/com/android/server/pm/Settings.java

总结

1. 和Google play store升级GMS有关系。
2. 原因:可能是某一步处理时,异步操作未正常结束导致packages.xml文件节点里面有未清除的数据,有可能是FOTA程序打断的。
3. 暂时未搞清楚,为什么GMS包会有这样被删除的动作。
    (方向有三点: 
    a. PR 157058 有一个修改. 
    b. suyibang 打的Google 的patch可能有问题。 
    c. Android 8.1自己平台的问题。)
4. 如需继续跟踪.
   (1. 编译USER版本,
    2. 并且需要打开相关LOG,
    3. 并且修改LOG工具开机迅速启动
    4. 需要google 翻墙WIFI
    5. 大量压力测试).
5. 从测试结果来看,第二种方案是安全的。