Android 8.1 系统。
1. E PackageManager: Failed to create app data for com.xxxx.iot.service, but trying to recover: com.android.server.pm.Installer$InstallerException: java.lang.NullPointerException: Attempt to invoke interface method 'long android.os.IInstalld.createAppData(java.lang.String, java.lang.String, int, int, int, java.lang.String, int)' on a null object reference
2. W PackageManager: com.android.server.pm.Installer$InstallerException: java.lang.NullPointerException: Attempt to invoke interface method 'void android.os.IInstalld.destroyAppData(java.lang.String, java.lang.String, int, int, long)' on a null object reference
3. D PackageManager: Recovery failed!
4. W PackageManager: Failed to migrate com.xxxx.iot.service: java.lang.NullPointerException: Attempt to invoke interface method 'void android.os.IInstalld.migrateAppData(java.lang.String, java.lang.String, int, int)' on a null object reference
从 log 中看出异常原因是调用 IInstalld 方法的时候抛出了空指针异常,IInstalld 其实就是 installd 在 SystemServer 中的代理,Java 层对应的 Service 是 Installer,在 systemServer 的 startBootstrapServices()
方法中连接 installd。
// frameworks/base/services/java/com/android/server/SystemServer.java
/**
* Starts the small tangle of critical services that are needed to get
* the system off the ground. These services have complex mutual dependencies
* which is why we initialize them all in one place here. Unless your service
* is also entwined in these dependencies, it should be initialized in one of
* the other functions.
*/
private void startBootstrapServices() {
...
Installer installer = mSystemServiceManager.startService(Installer.class);
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
...
}
Android 8.0 之前 SystemServer 与 installd 是通过 socket 连接的,在连接的时候会阻塞等待 installd 连接成功。
// frameworks/base/core/java/com/android/internal/os/InstallerConnection.java
public void waitForConnection() {
for (;;) {
try {
execute("ping");
return;
} catch (InstallerException ignored) {}
Slog.w(TAG, "installd not ready");
SystemClock.sleep(1000);
}}
但是在 Android 8.0 把 installd 的连接方式改成了 binder,且不会阻塞等待 installd 连接成功,而是每隔一秒重试,直到连接成功。
// frameworks/base/services/core/java/com/android/server/pm/Installer.java
private void connect() {
IBinder binder = ServiceManager.getService("installd");
if (binder != null) {
try {
binder.linkToDeath(new DeathRecipient() {
@Override
public void binderDied() {
Slog.w(TAG, "installd died; reconnecting");
connect();
}
}, 0);
} catch (RemoteException e) {
binder = null;
}
}
if (binder != null) {
mInstalld = IInstalld.Stub.asInterface(binder);
} else {
Slog.w(TAG, "installd not found; trying again");
// 一秒后重试
BackgroundThread.getHandler().postDelayed(() -> {
connect();
}, DateUtils.SECOND_IN_MILLIS);
}}
PackageManagerService(下面称为 PMS)的初始化也是在 startBootstrapServices()
方法中,且是在创建 Installer 对象之后。调用 PMS 的静态方法 main()
进行初始化,参数传入了 Installer 对象。
// frameworks/base/services/java/com/android/server/SystemServer.java
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
PMS 的初始化中会扫描 APK,并为应用创建私有目录。扫描 APK 时如果没有需要清除的 APK 则不会调用 installd,所以我们关注给应用创建私有目录的过程,它是调用 reconcileAppsDataLI()
方法。
// frameworks/base/services/core/java/com/android/server/pm/[PackageManagerService.java](<http://androidxref.com/8.0.0_r4/xref/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java>)
// Prepare storage for system user really early during boot,
// since core system apps like SettingsProvider and SystemUI
// can't wait for user to start
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL,
UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */,
true /* onlyCoreApps */);
FLAG_STORAGE_CE
指的是 /data/user/0/
,即 /data/data
,该目录只能在解锁屏幕后才能访问。而 FLAG_STORAGE_DE
指的是 /data/user_de/0
,该目录在有屏幕锁的时候也能访问,参考 Android 官网关于 DirectBoot 的介绍。
reconcileAppsDataLI()
方法中判断 ceDir
和 deDir
中的应用是否是已知的(参考系统启动时 PMS 检查 APK 有效性分析)且已安装的,如果不是的话调用 installd 的 destroyAppData()
函数删除对应私有目录。
之后对于已安装的应用调用 prepareAppDataAndMigrateLIF()
方法。
// frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
if (ps.getInstalled(userId)) {
prepareAppDataAndMigrateLIF(ps.pkg, userId, flags, migrateAppData);
preparedCount++;
}