Framework篇 – PackageManagerService 启动分析

本文源代码基于 Android 7.0。 

  • /base/services/java/com/android/server/SystemServer.java
  • /base/services/core/java/com/android/server/pm/PackageManagerService.java
  • /base/services/core/java/com/android/server/pm/Settings.java
  • /base/core/java/com/android/server/SystemConfig.java
  • /system/core/rootdir/init.rc
  • /base/cmds/installd/installd.cpp
  • /base/cmds/installd/commands.cpp
  • /base/cmds/installd/utils.cpp
  • /base/services/core/java/com/android/server/pm/Installer.java
  • /base/core/java/com/android/internal/os/InstallerConnection.java

PackageManagerService(PKMS),是 Android 系统中核心服务之一,管理着所有跟 package 相关的工作,常见的比如安装、卸载应用。 

 

目录:

  1. PKMS 的启动过程
  2. Installd 守护进程
  3. Installer

 

1. PMS 的启动过程

 

  • 1.1 SystemServer.startBootstrapServices()

PKMS 也是运行在 system_server 进程的,看看 SystemServer 的 startBootstrapServices():

private void startBootstrapServices() {
    //启动installer服务
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ...

    //处于加密状态则仅仅解析核心应用
    String cryptState = SystemProperties.get("vold.decrypt");
    if (ENCRYPTING_STATE.equals(cryptState)) {
        mOnlyCore = true; // ENCRYPTING_STATE = "trigger_restart_min_framework"
    } else if (ENCRYPTED_STATE.equals(cryptState)) {
        mOnlyCore = true; // ENCRYPTED_STATE = "1"
    }

    //创建PKMS对象
    mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
    //PKMS是否首次启动
    mFirstBoot = mPackageManagerService.isFirstBoot();


    mPackageManager = mSystemContext.getPackageManager();
    ...
}

PackageManagerService 与其他所有的服务一样,是由 SystemServer 启动,它也是 Java 层服务之一,PKMS.main() 过程主要是创建 PKMS 服务,并注册到 ServiceManager。整个 system_server 进程启动过程,涉及 PKMS 服务的主要几个动作如下,接下来分别讲解每个过程: 

  • PKMS.main() 
  • PKMS.performBootDexOpt 
  • PKMS.systemReady

 

  • 1.2 PKMS.main()
    public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        PackageManagerServiceCompilerMapping.checkProperties();

        // 构造一个包管理服务对象,new PackageManagerService
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        m.enableSystemUserPackages();
        CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
                UserHandle.USER_SYSTEM);
        // 将包管理服务对象添加到ServiceManager
        ServiceManager.addService("package", m);
        return m;
    }

该方法的主要功能创建 PKMS 对象,并将其注册到 ServiceManager。 关于 PKMS 对象的构造方法很长,分为以下几个阶段,
每个阶段会输出相应的 EventLog:除了阶段 1 的开头部分代码,后续代码都是同时持有同步锁 mPackages 和 mInstallLock 的过程中执行的。

  • 阶段1:BOOT_PROGRESS_PMS_START 
  • 阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 
  • 阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START 
  • 阶段4:BOOT_PROGRESS_PMS_SCAN_END 
  • 阶段5:BOOT_PROGRESS_PMS_READY

 

  • 1.3 阶段1:BOOT_PROGRESS_PMS_START

阶段1 PMS_START 有两部分组成,由无需加锁的前部分和同时持有两个锁的后半部分,先来说说前半部分: 

//向事件日志写入事件,标识PackageManagerService启动
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
        SystemClock.uptimeMillis());
//SDK版本检查
if (mSdkVersion <= 0) {
    Slog.w(TAG, "**** ro.build.version.sdk not set!");
}

mContext = context;
//开机模式是否为工厂模式
mFactoryTest = factoryTest;
//是否仅启动内核
mOnlyCore = onlyCore;
//构造DisplayMetrics对象以便获取尺寸数据
mMetrics = new DisplayMetrics();
//构造Settings对象存储运行时的设置信息
mSettings = new Settings(mPackages);
//添加一些用户uid
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);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
        ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
//判断是否在不同的进程
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
    if ("*".equals(separateProcesses)) {
        mDefParseFlags = PackageParser.PARSE_IGNORE_PROCESSES;
        mSeparateProcesses = null;
        Slog.w(TAG, "Running with debug.separate_processes: * (ALL)");
    } else {
        mDefParseFlags = 0;
        mSeparateProcesses = separateProcesses.split(",");
        Slog.w(TAG, "Running with debug.separate_processes: "
                + separateProcesses);
    }
} else {
    mDefParseFlags = 0;
    mSeparateProcesses = null;
}
//installer由SystemServer构造,这里通过该对象与底层进行通信,进行具体安装与卸载的操作
mInstaller = installer;
//创建PackageDexOptimizer,该类用于辅助进行dex优化
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
        "*dexopt*");
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());

mOnPermissionChangeListeners = new OnPermissionChangeListeners(
        FgThread.get().getLooper());

getDefaultDisplayMetrics(context, mMetrics);
//获取系统配置信息
SystemConfig systemConfig = SystemConfig.getInstance();
mGlobalGids = systemConfig.getGlobalGids();
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();

接下来,再来看看后半部分:

synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
    //启动消息处理线程
    mHandlerThread = new ServiceThread(TAG,
            Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
    mHandlerThread.start();
    //通过消息处理线程的Looper对象构造一个处理消息的Handler对象
    mHandler = new PackageHandler(mHandlerThread.getLooper());
    mProcessLoggingHandler = new ProcessLoggingHandler();
    //使用看门狗检测当前消息处理线程
    Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
    //获取当前的Data目录
    File dataDir = Environment.getDataDirectory();
    mAppInstallDir = new File(dataDir, "app");
    mAppLib32InstallDir = new File(dataDir, "app-lib");
    mEphemeralInstallDir = new File(dataDir, "app-ephemeral");
    mAsecInternalPath = new File(dataDir, "app-asec").getPath();
    mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
    //构造UserManagerService对象,创建用户管理服务
    sUserManager = new UserManagerService(context, this, mPackages);

    // Propagate permission configuration in to package manager.
    //读取权限配置文件中的信息,保存到mPermissions这个ArrayMap中
    ArrayMap<String, SystemConfig.PermissionEntry> permConfig
            = systemConfig.getPermissions();
    for (int i=0; i<permConfig.size(); i++) {
        SystemConfig.PermissionEntry perm = permConfig.valueAt(i);
        BasePermission bp = mSettings.mPermissions.get(perm.name);
        if (bp == null) {
            bp = new BasePermission(perm.name, "android", BasePermission.TYPE_BUILTIN);
            mSettings.mPermissions.put(perm.name, bp);
        }
        if (perm.gids != null) {
            bp.setGids(perm.gids, perm.perUser);
        }
    }
    //获取所有外部lib
    ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
    for (int i=0; i<libConfig.size(); i++) {
        mSharedLibraries.put(libConfig.keyAt(i),
                new SharedLibraryEntry(libConfig.valueAt(i), null));
    }
    //尝试读取mac_permissions.xml并解析
    mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();
    //读取并解析packages-backup.xml等文件
    mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false));
    //判断是否自定义的解析界面
    String customResolverActivity = Resources.getSystem().getString(
            R.string.config_customResolverActivity);
    if (TextUtils.isEmpty(customResolverActivity)) {
        customResolverActivity = null;
    } else {
        mCustomResolverComponentName = ComponentName.unflattenFromString(
                customResolverActivity);
    }
    ................
}

这个过程涉及的几个重要变量: 

  • mAppDataDir: /data/data
  • mAppLib32InstallDir: /data/app-lib
  • mAsecInternalPath: /data/app-asec
  • mUserAppDataDir: /data/user
  • mAppInstallDir: /data/app
  • mDrmAppPrivateInstallDir: /data/app-private

在阶段1中创建了 Settings 对象,来看看里面做了什么:

Settings(File dataDir, Object lock) {
    mLock = lock;

    mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);

    mSystemDir = new File(dataDir, "system");
    mSystemDir.mkdirs();//创建/data/system
    FileUtils.setPermissions(mSystemDir.toString(),
            FileUtils.S_IRWXU|FileUtils.S_IRWXG
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,
            -1, -1);
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    mPackageListFilename = new File(mSystemDir, "packages.list");
    FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);

    final File kernelDir = new File("/config/sdcardfs");
    mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;

    // Deprecated: Needed for migration
    mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
    mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}

此处 mSystemDir 是指目录 /data/system,在该目录有以下5个文件:

  • packages.xml: 记录所有安装的 app 信息
  • packages-backup.xml: 备份文件
  • packages-stopped.xml: 记录系统被强制停止的文件
  • packages-stopped-backup.xml: 备份文件
  • packages.list: 记录应用的数据信息

阶段1中还调用 SystemConfig.getInstance() 方法来获取 SystemConfig:

public static SystemConfig getInstance() {
    synchronized (SystemConfig.class) {
        if (sInstance == null) {
            sInstance = new SystemConfig();
        }
        return sInstance;
    }
}


SystemConfig() {
    // Read configuration from system
    readPermissions(Environment.buildPath(
            Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
    // Read configuration from the old permissions dir
    readPermissions(Environment.buildPath(
            Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
    // Allow ODM to customize system configs around libs, features and apps
    int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
    readPermissions(Environment.buildPath(
            Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
    readPermissions(Environment.buildPath(
            Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
    // Only allow OEM to customize features
    readPermissions(Environment.buildPath(
            Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
    readPermissions(Environment.buildPath(
            Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
}

readPermissions() 解析指定目录下的所有 xml 文件,比如将标签所指的动态库保存到 PKMS 的成员变量 mSharedLibraries。
可见,SystemConfig 创建过程是对以下这六个目录中的所有 xml 进行解析: 

  • /system/etc/sysconfig 
  • /system/etc/permissions 
  • /odm/etc/sysconfig 
  • /odm/etc/permissions 
  • /oem/etc/sysconfig 
  • /oem/etc/permissions
void readPermissions(File libraryDir, int permissionFlag) {
    // Read permissions from given directory.
    if (!libraryDir.exists() || !libraryDir.isDirectory()) {
        if (permissionFlag == ALLOW_ALL) {
            Slog.w(TAG, "No directory " + libraryDir + ", skipping");
        }
        return;
    }
    if (!libraryDir.canRead()) {
        Slog.w(TAG, "Directory " + libraryDir + " cannot be read");
        return;
    }

    // Iterate over the files in the directory and scan .xml files
    File platformFile = null;
    for (File f : libraryDir.listFiles()) {
        // We'll read platform.xml last
        if (f.getPath().endsWith("etc/permissions/platform.xml")) {
            platformFile = f;
            continue;
        }

        if (!f.getPath().endsWith(".xml")) {
            Slog.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
            continue;
        }
        if (!f.canRead()) {
            Slog.w(TAG, "Permissions library file " + f + " cannot be read");
            continue;
        }

        readPermissionsFromXml(f, permissionFlag);
    }

    // Read platform permissions last so it will take precedence
    if (platformFile != null) {
        readPermissionsFromXml(platformFile, permissionFlag);
    }
}

该方法是解析指定目录下所有的具有可读权限的,且以 xml 为后缀文件。

 

  • 1.4 阶段2:BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
            //标记扫描开始的时间
            long startTime = SystemClock.uptimeMillis();
            //将扫描开始的事件写入日志
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
                    startTime);

            // Set flag to monitor and not change apk file paths when
            // scanning install directories.
            //设置扫描的模式
            final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING | SCAN_INITIAL;
            //获取java启动类库的路径
            final String bootClassPath = System.getenv("BOOTCLASSPATH");
            //获取systemServer的路径
            final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");

            if (bootClassPath == null) {
                Slog.w(TAG, "No BOOTCLASSPATH found!");
            }

            if (systemServerClassPath == null) {
                Slog.w(TAG, "No SYSTEMSERVERCLASSPATH found!");
            }

            final List<String> allInstructionSets = InstructionSets.getAllInstructionSets();
            final String[] dexCodeInstructionSets =
                    getDexCodeInstructionSets(
                            allInstructionSets.toArray(new String[allInstructionSets.size()]));

            /**
             * Ensure all external libraries have had dexopt run on them.
             */
            //确保所有的外部lib都被dexopt优化
            if (mSharedLibraries.size() > 0) {
                // NOTE: For now, we're compiling these system "shared libraries"
                // (and framework jars) into all available architectures. It's possible
                // to compile them only when we come across an app that uses them (there's
                // already logic for that in scanPackageLI) but that adds some complexity.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
                        final String lib = libEntry.path;
                        if (lib == null) {
                            continue;
                        }

                        try {
                            // Shared libraries do not have profiles so we perform a full
                            // AOT compilation (if needed).
                            int dexoptNeeded = DexFile.getDexOptNeeded(
                                    lib, dexCodeInstructionSet,
                                    getCompilerFilterForReason(REASON_SHARED_APK),
                                    false /* newProfile */);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
                                        getCompilerFilterForReason(REASON_SHARED_APK),
                                        StorageManager.UUID_PRIVATE_INTERNAL,
                                        SKIP_SHARED_LIBRARY_CHECK);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException | InstallerException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }

            File frameworkDir = new File(Environment.getRootDirectory(), "framework");

            final VersionInfo ver = mSettings.getInternalVersion();
            mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);

            // when upgrading from pre-M, promote system app permissions from install to runtime
            mPromoteSystemApps =
                    mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;

            // When upgrading from pre-N, we need to handle package extraction like first boot,
            // as there is no profiling data available.
            mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;

            // save off the names of pre-existing system packages prior to scanning; we don't
            // want to automatically grant runtime permissions for new system apps
            if (mPromoteSystemApps) {
                Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
                while (pkgSettingIter.hasNext()) {
                    PackageSetting ps = pkgSettingIter.next();
                    if (isSystemApp(ps)) {
                        mExistingSystemPackages.add(ps.name);
                    }
                }
            }

            // Collect vendor overlay packages.
            // (Do this before scanning any apps.)
            // For security and version matching reason, only consider
            // overlay packages if they reside in VENDOR_OVERLAY_DIR.
            //收集供应商包名:/vendor/overlay
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirTracedLI(vendorOverlayDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

            // Find base frameworks (resource packages without code).
            //扫描frameworkDir目录下的apk进行安装,扫描模式为非优化模式
            scanDirTracedLI(frameworkDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

            // Collected privileged system packages.
            final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
            scanDirTracedLI(privilegedAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);

            // Collect ordinary system packages.
            final File systemAppDir = new File(Environment.getRootDirectory(), "app");
            scanDirTracedLI(systemAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // Collect all vendor packages.
            File vendorAppDir = new File("/vendor/app");
            try {
                vendorAppDir = vendorAppDir.getCanonicalFile();
            } catch (IOException e) {
                // failed to look up canonical path, continue with original one
            }
            scanDirTracedLI(vendorAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // Collect all OEM packages.
            final File oemAppDir = new File(Environment.getOemDirectory(), "app");
            scanDirTracedLI(oemAppDir, mDefParseFlags
                    | PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

            // Prune any system packages that no longer exist.
            //构造一个List来存放不存在的packages路径
            final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();
            if (!mOnlyCore) {
                //遍历mSettings.mPackages
                Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
                while (psit.hasNext()) {
                    PackageSetting ps = psit.next();

                    /*
                     * If this is not a system app, it can't be a
                     * disable system app.
                     */
                    //如果不是系统app,不处理
                    if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                        continue;
                    }

                    /*
                     * If the package is scanned, it's not erased.
                     */
                    final PackageParser.Package scannedPkg = mPackages.get(ps.name);
                    if (scannedPkg != null) {
                        /*
                         * If the system app is both scanned and in the
                         * disabled packages list, then it must have been
                         * added via OTA. Remove it from the currently
                         * scanned package so the previously user-installed
                         * application can be scanned.
                         */
                        //如果在disable列表中,那么,说明它是通过OTA方式进行升级更新添加的,因此,清楚相应数据
                        if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
                            logCriticalInfo(Log.WARN, "Expecting better updated system app for "
                                    + ps.name + "; removing system app.  Last known codePath="
                                    + ps.codePathString + ", installStatus=" + ps.installStatus
                                    + ", versionCode=" + ps.versionCode + "; scanned versionCode="
                                    + scannedPkg.mVersionCode);
                            //移除其信息
                            removePackageLI(scannedPkg, true);
                            mExpectingBetter.put(ps.name, ps.codePath);
                        }

                        continue;
                    }
                    //如果不在disable列表中,则直接清楚相应的数据
                    if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
                        psit.remove();
                        logCriticalInfo(Log.WARN, "System package " + ps.name
                                + " no longer exists; it's data will be wiped");
                        // Actual deletion of code and data will be handled by later
                        // reconciliation step
                    } else {
                        //否则,通过codePath判断其是否有可能被更新或删除
                        final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
                        if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
                            possiblyDeletedUpdatedSystemApps.add(ps.name);
                        }
                    }
                }
            }

            //look for any incomplete package installations
            //获取未完成安装的apk包的PackageSetting列表
            ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
            //清除未安装的安装包
            for (int i = 0; i < deletePkgsList.size(); i++) {
                // Actual deletion of code and data will be handled by later
                // reconciliation step
                final String packageName = deletePkgsList.get(i).name;
                logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + packageName);
                synchronized (mPackages) {
                    mSettings.removePackageLPw(packageName);
                }
            }

            //delete tmp files
            //清除临时文件
            deleteTempPackageFiles();

            // Remove any shared userIDs that have no associated packages
            //清除在mSettings中没有被使用的SharedUserSettings
            mSettings.pruneSharedUsersLPw();
  • 环境变量:那可通过 adb shell env 来查看系统所有的环境变量及相应值。也可通过命令 adb shell echo $SYSTEMSERVERCLASSPATH。 
  • SYSTEMSERVERCLASSPATH:主要包括 /system/framework 目录下 services.jar,ethernet-service.jar,wifi-service.jar 这3个文件。 
  • BOOTCLASSPATH:该环境变量内容较多,不同 ROM 可能有所不同,常见内容包含 /system/framework 目录下的framework.jar,ext.jar,core-libart.jar,telephony-common.jar,ims-common.jar,core-junit.jar 等文件。
  • scanDirLI():扫描指定目录下的 apk 文件,最终调用 PackageParser.parseBaseApk 来完成 AndroidManifest.xml 文件的解析,生成 Application, activity, service, broadcast, provider 等信息。 

/vendor/overlay 
/system/framework 
/system/priv-app 
/system/app 
/vendor/priv-app 
/vendor/app 
/oem/app

 

  • 1.5 阶段3:BOOT_PROGRESS_PMS_DATA_SCAN_START
/ Remove any shared userIDs that have no associated packages
//清除在mSettings中没有被使用的SharedUserSettings
mSettings.pruneSharedUsersLPw();
//如果是普通模式,则需要进行一些额外处理
if (!mOnlyCore) {
    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
            SystemClock.uptimeMillis());
    //扫描该目录
    scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);

    scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
            | PackageParser.PARSE_FORWARD_LOCK,
            scanFlags | SCAN_REQUIRE_KNOWN, 0);

    scanDirLI(mEphemeralInstallDir, mDefParseFlags
            | PackageParser.PARSE_IS_EPHEMERAL,
            scanFlags | SCAN_REQUIRE_KNOWN, 0);

    /**
     * Remove disable package settings for any updated system
     * apps that were removed via an OTA. If they're not a
     * previously-updated app, remove them completely.
     * Otherwise, just revoke their system-level permissions.
     */
    //后面这部分代码逻辑简单,就是遍历possiblyDeletedUpdatedSystemApps,处理通过OTA更新和删除的APK文件
    for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
        PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
        mSettings.removeDisabledSystemPackageLPw(deletedAppName);

        String msg;
        if (deletedPkg == null) {
            msg = "Updated system package " + deletedAppName
                    + " no longer exists; it's data will be wiped";
            // Actual deletion of code and data will be handled by later
            // reconciliation step
        } else {
            msg = "Updated system app + " + deletedAppName
                    + " no longer present; removing system privileges for "
                    + deletedAppName;

            deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;

            PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
            deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
        }
        logCriticalInfo(Log.WARN, msg);
    }

    /**
     * Make sure all system apps that we expected to appear on
     * the userdata partition actually showed up. If they never
     * appeared, crawl back and revive the system version.
     */
    for (int i = 0; i < mExpectingBetter.size(); i++) {
        final String packageName = mExpectingBetter.keyAt(i);
        if (!mPackages.containsKey(packageName)) {
            final File scanFile = mExpectingBetter.valueAt(i);

            logCriticalInfo(Log.WARN, "Expected better " + packageName
                    + " but never showed up; reverting to system");

            int reparseFlags = mDefParseFlags;
            if (FileUtils.contains(privilegedAppDir, scanFile)) {
                reparseFlags = PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR
                        | PackageParser.PARSE_IS_PRIVILEGED;
            } else if (FileUtils.contains(systemAppDir, scanFile)) {
                reparseFlags = PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR;
            } else if (FileUtils.contains(vendorAppDir, scanFile)) {
                reparseFlags = PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR;
            } else if (FileUtils.contains(oemAppDir, scanFile)) {
                reparseFlags = PackageParser.PARSE_IS_SYSTEM
                        | PackageParser.PARSE_IS_SYSTEM_DIR;
            } else {
                Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
                continue;
            }

            mSettings.enableSystemPackageLPw(packageName);

            try {
                scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);
            } catch (PackageManagerException e) {
                Slog.e(TAG, "Failed to parse original system package: "
                        + e.getMessage());
            }
        }
    }
}
mExpectingBetter.clear();

// Resolve protected action filters. Only the setup wizard is allowed to
// have a high priority filter for these actions.
mSetupWizardPackage = getSetupWizardPackageName();
if (mProtectedFilters.size() > 0) {
    if (DEBUG_FILTERS && mSetupWizardPackage == null) {
        Slog.i(TAG, "No setup wizard;"
            + " All protected intents capped to priority 0");
    }
    for (ActivityIntentInfo filter : mProtectedFilters) {
        if (filter.activity.info.packageName.equals(mSetupWizardPackage)) {
            if (DEBUG_FILTERS) {
                Slog.i(TAG, "Found setup wizard;"
                    + " allow priority " + filter.getPriority() + ";"
                    + " package: " + filter.activity.info.packageName
                    + " activity: " + filter.activity.className
                    + " priority: " + filter.getPriority());
            }
            // skip setup wizard; allow it to keep the high priority filter
            continue;
        }
        Slog.w(TAG, "Protected action; cap priority to 0;"
                + " package: " + filter.activity.info.packageName
                + " activity: " + filter.activity.className
                + " origPrio: " + filter.getPriority());
        filter.setPriority(0);
    }
}
mDeferProtectedFilters = false;
mProtectedFilters.clear();

// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
//给需要使用shared libraries的package找到相应的路径,并将其保存至package的usesLibraryFiles中
updateAllSharedLibrariesLPw();

for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
    // NOTE: We ignore potential failures here during a system scan (like
    // the rest of the commands above) because there's precious little we
    // can do about it. A settings error is reported, though.
    adjustCpuAbisForSharedUserLPw(setting.packages, null /* scanned package */,
            false /* boot complete */);
}

// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.readLP();

当 mOnlyCore = false 时,则 scanDirLI() 还会收集如下目录中的 apk:

  • /data/app 
  • /data/app-private 

 

  • 1.6 阶段4:BOOT_PROGRESS_PMS_SCAN_END
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
                    SystemClock.uptimeMillis());
            Slog.i(TAG, "Time to scan packages: "
                    + ((SystemClock.uptimeMillis()-startTime)/1000f)
                    + " seconds");

            // If the platform SDK has changed since the last time we booted,
            // we need to re-grant app permission to catch any new ones that
            // appear.  This is really a hack, and means that apps can in some
            // cases get permissions that the user didn't initially explicitly
            // allow...  it would be nice to have some better way to handle
            // this situation.
            int updateFlags = UPDATE_PERMISSIONS_ALL;
            if (ver.sdkVersion != mSdkVersion) {
                Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
                        + mSdkVersion + "; regranting permissions for internal storage");
                updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
            }
            //当sdk版本不一致时,,更新相关信息,并给需要使用权限的apk分配相应的权限
            updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
            ver.sdkVersion = mSdkVersion;

            // If this is the first boot or an update from pre-M, and it is a normal
            // boot, then we need to initialize the default preferred apps across
            // all defined users.
            //当这是ota后的首次启动,正常启动则需要清除目录的缓存代码
            if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
                for (UserInfo user : sUserManager.getUsers(true)) {
                    mSettings.applyDefaultPreferredAppsLPw(this, user.id);
                    applyFactoryDefaultBrowserLPw(user.id);
                    primeDomainVerificationsLPw(user.id);
                }
            }

            // 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;
            }
            reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM,
                    storageFlags);

            // If this is first boot after an OTA, and a normal boot, then
            // we need to clear code cache directories.
            // Note that we do *not* clear the application profiles. These remain valid
            // across OTAs and are used to drive profile verification (post OTA) and
            // profile compilation (without waiting to collect a fresh set of profiles).
            if (mIsUpgrade && !onlyCore) {
                Slog.i(TAG, "Build fingerprint changed; clearing code caches");
                for (int i = 0; i < mSettings.mPackages.size(); i++) {
                    final PackageSetting ps = mSettings.mPackages.valueAt(i);
                    if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
                        // No apps are running this early, so no need to freeze
                        clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
                                StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
                                        | Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
                    }
                }
                ver.fingerprint = Build.FINGERPRINT;
            }

            checkDefaultBrowser();

            // clear only after permissions and other defaults have been updated
            //当权限和其他默认项都完成更新,则清理相关信息
            mExistingSystemPackages.clear();
            mPromoteSystemApps = false;

            // All the changes are done during package scanning.
            ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;

            // can downgrade to reader
            //信息写回packages.xml文件
            mSettings.writeLPr();

            // Perform dexopt on all apps that mark themselves as coreApps. We do this pretty
            // early on (before the package manager declares itself as early) because other
            // components in the system server might ask for package contexts for these apps.
            //
            // Note that "onlyCore" in this context means the system is encrypted or encrypting
            // (i.e, that the data partition is unavailable).
            if ((isFirstBoot() || isUpgrade() || VMRuntime.didPruneDalvikCache()) && !onlyCore) {
                long start = System.nanoTime();
                List<PackageParser.Package> coreApps = new ArrayList<>();
                for (PackageParser.Package pkg : mPackages.values()) {
                    if (pkg.coreApp) {
                        coreApps.add(pkg);
                    }
                }

                int[] stats = performDexOpt(coreApps, false,
                        getCompilerFilterForReason(REASON_CORE_APP));

                final int elapsedTimeSeconds =
                        (int) TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start);
                MetricsLogger.histogram(mContext, "opt_coreapps_time_s", elapsedTimeSeconds);

                if (DEBUG_DEXOPT) {
                    Slog.i(TAG, "Dex-opt core apps took : " + elapsedTimeSeconds + " seconds (" +
                            stats[0] + ", " + stats[1] + ", " + stats[2] + ")");
                }


                // TODO: Should we log these stats to tron too ?
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_dexopted", stats[0]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_skipped", stats[1]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_failed", stats[2]);
                // MetricsLogger.histogram(mContext, "opt_coreapps_num_total", coreApps.size());
            }

 

  • 1.7 阶段5:BOOT_PROGRESS_PMS_READY
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
                    SystemClock.uptimeMillis());

            if (!mOnlyCore) {
                mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr();
                mRequiredInstallerPackage = getRequiredInstallerLPr();
                mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr();
                mIntentFilterVerifier = new IntentVerifierProxy(mContext,
                        mIntentFilterVerifierComponent);
                mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                        PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);
            } else {
                mRequiredVerifierPackage = null;
                mRequiredInstallerPackage = null;
                mIntentFilterVerifierComponent = null;
                mIntentFilterVerifier = null;
                mServicesSystemSharedLibraryPackageName = null;
                mSharedSystemSharedLibraryPackageName = null;
            }

            mInstallerService = new PackageInstallerService(context, this);

            final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr();
            final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr();
            // both the installer and resolver must be present to enable ephemeral
            if (ephemeralInstallerComponent != null && ephemeralResolverComponent != null) {
                if (DEBUG_EPHEMERAL) {
                    Slog.i(TAG, "Ephemeral activated; resolver: " + ephemeralResolverComponent
                            + " installer:" + ephemeralInstallerComponent);
                }
                mEphemeralResolverComponent = ephemeralResolverComponent;
                mEphemeralInstallerComponent = ephemeralInstallerComponent;
                setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent);
                mEphemeralResolverConnection =
                        new EphemeralResolverConnection(mContext, mEphemeralResolverComponent);
            } else {
                if (DEBUG_EPHEMERAL) {
                    final String missingComponent =
                            (ephemeralResolverComponent == null)
                            ? (ephemeralInstallerComponent == null)
                                    ? "resolver and installer"
                                    : "resolver"
                            : "installer";
                    Slog.i(TAG, "Ephemeral deactivated; missing " + missingComponent);
                }
                mEphemeralResolverComponent = null;
                mEphemeralInstallerComponent = null;
                mEphemeralResolverConnection = null;
            }

            mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this);
        } // synchronized (mPackages)
        } // synchronized (mInstallLock)

        // Now after opening every single application zip, make sure they
        // are all flushed.  Not really needed, but keeps things nice and
        // tidy.
        Runtime.getRuntime().gc();

        // The initial scanning above does many calls into installd while
        // holding the mPackages lock, but we're mostly interested in yelling
        // once we have a booted system.
        mInstaller.setWarnIfHeld(mPackages);

        // Expose private service for system components to use.
        LocalServices.addService(PackageManagerInternal.class, new                     PackageManagerInternalImpl());

 

  • 1.8 PackageInstaller 服务

PKMS 初始化完成阶段,还会创建一个 PackageInstaller 服务。

public PackageInstallerService(Context context, PackageManagerService pm) {
    mContext = context;
    mPm = pm;
    //创建名为”PackageInstaller“的Handler线程
    mInstallThread = new HandlerThread(TAG);
    mInstallThread.start();

    mInstallHandler = new Handler(mInstallThread.getLooper());

    mCallbacks = new Callbacks(mInstallThread.getLooper());

    mSessionsFile = new AtomicFile(
            new File(Environment.getSystemSecureDirectory(), "install_sessions.xml"));
    mSessionsDir = new File(Environment.getSystemSecureDirectory(), "install_sessions");
    mSessionsDir.mkdirs();

    synchronized (mSessions) {
        readSessionsLocked();

        reconcileStagesLocked(StorageManager.UUID_PRIVATE_INTERNAL);

        final ArraySet<File> unclaimedIcons = newArraySet(
                mSessionsDir.listFiles());

        for (int i = 0; i < mSessions.size(); i++) {
            final PackageInstallerSession session = mSessions.valueAt(i);
            unclaimedIcons.remove(buildAppIconFile(session.sessionId));
        }

        for (File icon : unclaimedIcons) {
            icon.delete();
        }
    }
}

PKMS 初始化过程,分为5个阶段: 

PMS_START 阶段: 

  • 创建 Settings 对象; 
  • 将6类 shareUserId 到 mSettings; 
  • 初始化 SystemConfig; 
  • 创建名为 “PackageManager” 的 handler 线程 mHandlerThread; 
  • 创建 UserManagerService 多用户管理服务; 
  • 通过解析4大目录中的 xml 文件构造共享 mSharedLibraries; 

PMS_SYSTEM_SCAN_START 阶段: 

  • 扫描系统 apk; 

PMS_DATA_SCAN_START 阶段: 

  • 扫描 /data/app 目录下的 apk; 
  • 扫描 /data/app-private 目录下的 apk; 

PMS_SCAN_END 阶段: 

  • 将上述信息写回 /data/system/packages.xml; 

PMS_READY 阶段: 

  • 创建服务 PackageInstallerService;

 

  • 1.9 PKMS.systemReady
@Override
    public void systemReady() {
        mSystemReady = true;

        // Read the compatibilty setting when the system is ready.
        boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
                mContext.getContentResolver(),
                android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
        PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
        if (DEBUG_SETTINGS) {
            Log.d(TAG, "compatibility mode:" + compatibilityModeEnabled);
        }

        int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;

        synchronized (mPackages) {
            ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
            for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
                PreferredIntentResolver pir = mSettings.mPreferredActivities.valueAt(i);
                removed.clear();
                for (PreferredActivity pa : pir.filterSet()) {
                    if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {
                        removed.add(pa);
                    }
                }
                if (removed.size() > 0) {
                    for (int r=0; r<removed.size(); r++) {
                        PreferredActivity pa = removed.get(r);
                        Slog.w(TAG, "Removing dangling preferred activity: "
                                + pa.mPref.mComponent);
                        pir.removeFilter(pa);
                    }
                    mSettings.writePackageRestrictionsLPr(
                            mSettings.mPreferredActivities.keyAt(i));
                }
            }

            for (int userId : UserManagerService.getInstance().getUserIds()) {
                if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
                    grantPermissionsUserIds = ArrayUtils.appendInt(
                            grantPermissionsUserIds, userId);
                }
            }
        }
        sUserManager.systemReady();//多用户服务

        // If we upgraded grant all default permissions before kicking off.
        //升级所有已获取的默认权限
        for (int userId : grantPermissionsUserIds) {
            mDefaultPermissionPolicy.grantDefaultPermissions(userId);
        }

        // Kick off any messages waiting for system ready
        //处理所有等待系统准备就绪的消息
        if (mPostSystemReadyMessages != null) {
            for (Message msg : mPostSystemReadyMessages) {
                msg.sendToTarget();
            }
            mPostSystemReadyMessages = null;
        }

        // Watch for external volumes that come and go over time
        //观察外部存储设备
        final StorageManager storage = mContext.getSystemService(StorageManager.class);
        storage.registerListener(mStorageListener);

        mInstallerService.systemReady();
        mPackageDexOptimizer.systemReady();

        MountServiceInternal mountServiceInternal = LocalServices.getService(
                MountServiceInternal.class);
        mountServiceInternal.addExternalStoragePolicy(
                new MountServiceInternal.ExternalStorageMountPolicy() {
            @Override
            public int getMountMode(int uid, String packageName) {
                if (Process.isIsolated(uid)) {
                    return Zygote.MOUNT_EXTERNAL_NONE;
                }
                if (checkUidPermission(WRITE_MEDIA_STORAGE, uid) == PERMISSION_GRANTED) {
                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
                }
                if (checkUidPermission(READ_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                    return Zygote.MOUNT_EXTERNAL_DEFAULT;
                }
                if (checkUidPermission(WRITE_EXTERNAL_STORAGE, uid) == PERMISSION_DENIED) {
                    return Zygote.MOUNT_EXTERNAL_READ;
                }
                return Zygote.MOUNT_EXTERNAL_WRITE;
            }

            @Override
            public boolean hasExternalStorage(int uid, String packageName) {
                return true;
            }
        });

        reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
        reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
    }

至此,PackageManagerService 启动流程分析完毕。

 

 

2. Installd 守护进程

PKMS 服务负责应用的安装、卸载等相关工作,而真正干活的还是 installd。其中 PKMS 执行权限为 system,而进程 installd 的执行权限为 root。

 

  • 2.1 简介

installd 是由 Android 系统的 init 进程 (pid=1),在解析 init.rc 文件的如下代码块时,通过 fork 创建的用户空间的守护进程 installd。

service installd /system/bin/installd
class main
socket installd stream 600 system system

installd 是随着系统启动过程中 main class 而启动的,并且会创建一个 socket 套接字,用于跟上层的 PKMS 进行交互。
installd 的启动入口 /base/cmds/installd/installd.c 的 main() 方法,接下来从这里开始说起。

 

  • 2.2 installd 启动

installd.cpp

int main(const int argc __unused, char *argv[]) {
    char buf[BUFFER_MAX]; //buffer大小为1024Byte
    struct sockaddr addr;
    socklen_t alen;
    int lsocket, s;
    ...

    //初始化全局信息
    if (initialize_globals() < 0) {
            exit(1);
    }
    
    //初始化相关目录
    if (initialize_directories() < 0) {
        exit(1);
    }
    
    //获取套接字"installd"
    lsocket = android_get_control_socket(SOCKET_PATH);
    
    if (listen(lsocket, 5)) { //监听socket消息
        exit(1);
    }
    fcntl(lsocket, F_SETFD, FD_CLOEXEC);

    for (;;) {
        alen = sizeof(addr);
        s = accept(lsocket, &addr, &alen); //接受socket消息
        if (s < 0) {
            continue;
        }
        fcntl(s, F_SETFD, FD_CLOEXEC);

        for (;;) {
            unsigned short count;
            //读取指令的长度
            if (readx(s, &count, sizeof(count))) {
                break;
            }
            if ((count < 1) || (count >= BUFFER_MAX)) {
                break;
            }
            //读取指令的内容
            if (readx(s, buf, count)) {
                break;
            }
            buf[count] = 0;
            ...
            
            //执行指令
            if (execute(s, buf)) break;
        }
        close(s);
    }
    return 0;
}

installd 进程,通过监听套接字 “installd”,当接收到 socket 消息则执行相应的指令。

int initialize_globals() {
    // 数据目录/data/
    if (get_path_from_env(&android_data_dir, "ANDROID_DATA") < 0) {
        return -1;
    }

    // app目录/data/app/
    if (copy_and_append(&android_app_dir, &android_data_dir, APP_SUBDIR) < 0) {
        return -1;
    }

    // 受保护的app目录/data/priv-app/
    if (copy_and_append(&android_app_private_dir, &android_data_dir, PRIVATE_APP_SUBDIR) < 0) {
        return -1;
    }

    // app本地库目录/data/app-lib/
    if (copy_and_append(&android_app_lib_dir, &android_data_dir, APP_LIB_SUBDIR) < 0) {
        return -1;
    }

    // sdcard挂载点/mnt/asec
    if (get_path_from_env(&android_asec_dir, "ASEC_MOUNTPOINT") < 0) {
        return -1;
    }

    // 多媒体目录/data/media
    if (copy_and_append(&android_media_dir, &android_data_dir, MEDIA_SUBDIR) < 0) {
        return -1;
    }

    // 外部app目录/mnt/expand
    if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
        return -1;
    }

    // 系统和厂商目录
    android_system_dirs.count = 4;

    android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
    ...

    dir_rec_t android_root_dir;
    // 目录/system
    if (get_path_from_env(&android_root_dir, "ANDROID_ROOT") < 0) {
        return -1;
    }

    // 目录/system/app
    android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
    android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
    
    // 目录/system/app-lib
    android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
    android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);

    // 目录/vendor/app/
    android_system_dirs.dirs[2].path = strdup("/vendor/app/");
    android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);

    // 目录/oem/app/
    android_system_dirs.dirs[3].path = strdup("/oem/app/");
    android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);

    return 0;
}
int initialize_directories() {
    int res = -1;

    //读取当前文件系统版本
    char version_path[PATH_MAX];
    snprintf(version_path, PATH_MAX, "%s.layout_version", android_data_dir.path);

    int oldVersion;
    if (fs_read_atomic_int(version_path, &oldVersion) == -1) {
        oldVersion = 0;
    }
    int version = oldVersion;

    // 目录/data/user
    char *user_data_dir = build_string2(android_data_dir.path, SECONDARY_USER_PREFIX);
    // 目录/data/data
    char *legacy_data_dir = build_string2(android_data_dir.path, PRIMARY_USER_PREFIX);
    // 目录/data/user/0
    char *primary_data_dir = build_string3(android_data_dir.path, SECONDARY_USER_PREFIX, "0");
    ...

    //将/data/user/0链接到/data/data
    if (access(primary_data_dir, R_OK) < 0) {
        if (symlink(legacy_data_dir, primary_data_dir)) {
            goto fail;
        }
    }

    ... //处理data/media 相关
    
    return res;
}
static int execute(int s, char cmd[BUFFER_MAX]) {
    char reply[REPLY_MAX];
    char *arg[TOKEN_MAX+1];
    unsigned i;
    unsigned n = 0;
    unsigned short count;
    int ret = -1;
    reply[0] = 0;

    arg[0] = cmd;
    while (*cmd) {
        if (isspace(*cmd)) {
            *cmd++ = 0;
            n++;
            arg[n] = cmd;
            if (n == TOKEN_MAX) {
                goto done;
            }
        }
        if (*cmd) {
          cmd++; //计算参数个数
        }
    }

    for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
        if (!strcmp(cmds[i].name,arg[0])) {
            if (n != cmds[i].numargs) {
                //参数个数不匹配,直接返回
                ALOGE("%s requires %d arguments (%d given)\n",
                    cmds[i].name, cmds[i].numargs, n);
            } else {
                //执行相应的命令
                ret = cmds[i].func(arg + 1, reply);
            }
            goto done;
        }
    }

done:
    if (reply[0]) {
        n = snprintf(cmd, BUFFER_MAX, "%d %s", ret, reply);
    } else {
        n = snprintf(cmd, BUFFER_MAX, "%d", ret);
    }
    if (n > BUFFER_MAX) n = BUFFER_MAX;
    count = n;
    
    //将命令执行后的返回值写入socket套接字
    if (writex(s, &count, sizeof(count))) return -1;
    if (writex(s, cmd, count)) return -1;
    return 0;
}

 

  • 2.3 命令表
struct cmdinfo cmds[] = {
    { "ping",                 0, do_ping },
    { "install",              5, do_install }, //安装app
    { "dexopt",               9, do_dexopt }, //dex优化
    { "markbootcomplete",     1, do_mark_boot_complete },
    { "movedex",              3, do_move_dex },
    { "rmdex",                2, do_rm_dex },
    { "remove",               3, do_remove },
    { "rename",               2, do_rename },
    { "fixuid",               4, do_fixuid },
    { "freecache",            2, do_free_cache },
    { "rmcache",              3, do_rm_cache },
    { "rmcodecache",          3, do_rm_code_cache },
    { "getsize",              8, do_get_size },
    { "rmuserdata",           3, do_rm_user_data },
    { "cpcompleteapp",        6, do_cp_complete_app },
    { "movefiles",            0, do_movefiles },
    { "linklib",              4, do_linklib },
    { "mkuserdata",           5, do_mk_user_data },
    { "mkuserconfig",         1, do_mk_user_config },
    { "rmuser",               2, do_rm_user },
    { "idmap",                3, do_idmap },
    { "restorecondata",       4, do_restorecon_data },
    { "createoatdir",         2, do_create_oat_dir },
    { "rmpackagedir",         1, do_rm_package_dir },
    { "linkfile",             3, do_link_file }
};

此命令表总共有25的命令,该表中第二列是指命令所需的参数个数,第三列是指命令所指向的函数。不同的 Android 版本该表格都会有所不同。

 

 

3. Installer

当守护进程 installd 启动完成后,上层 framework 便可以通过 socket 跟该守护进程进行通信。 在 SystemServer 启动服务的过程中创建 Installer 对象,便会有一次跟 installd 通信的过程。

SystemServer.java

private void startBootstrapServices() {
    //启动installer服务
    Installer installer = mSystemServiceManager.startService(Installer.class);
    ...
}

Installer.java

public Installer(Context context) {
    super(context);
    // 创建InstallerConnection对象
    mInstaller = new InstallerConnection();
}

public void onStart() {
  Slog.i(TAG, "Waiting for installd to be ready.");
  mInstaller.waitForConnection();
}

先创建 Installer 对象,再调用 onStart() 方法,该方法中主要工作是等待 socket 通道建立完成。

InstallerConnection.java

    public void waitForConnection() {
        for (;;) {
            try {
                execute("ping");
                return;
            } catch (InstallerException ignored) {
            }
            Slog.w(TAG, "installd not ready");
            SystemClock.sleep(1000);
        }
    }

    public String[] execute(String cmd, Object... args) throws InstallerException {
        final StringBuilder builder = new StringBuilder(cmd);
        for (Object arg : args) {
            String escaped;
            if (arg == null) {
                escaped = "";
            } else {
                escaped = String.valueOf(arg);
            }
            if (escaped.indexOf('\0') != -1 || escaped.indexOf(' ') != -1 || "!".equals(escaped)) {
                throw new InstallerException(
                        "Invalid argument while executing " + cmd + " " + Arrays.toString(args));
            }
            if (TextUtils.isEmpty(escaped)) {
                escaped = "!";
            }
            builder.append(' ').append(escaped);
        }
        // 执行transact函数
        final String[] resRaw = transact(builder.toString()).split(" ");
        int res = -1;
        try {
            res = Integer.parseInt(resRaw[0]);
        } catch (ArrayIndexOutOfBoundsException | NumberFormatException ignored) {
        }
        if (res != 0) {
            throw new InstallerException(
                    "Failed to execute " + cmd + " " + Arrays.toString(args) + ": " + res);
        }
        return resRaw;
    }

        /**
     * 可见,一次transact过程为先connect()来判断是否建立socket连接,如果已连接则通过writeCommand() 将命令写入socket的mOut管道,
     * 等待从管道的mIn中readFully()读取应答消息。
     *
     * 上层PackageManagerService收集完相应信息,通过socket交给守护进程installd,该进程才是真正干活的进程。
     */
    public synchronized String transact(String cmd) {
        if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) {
            Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x"
                    + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable());
        }

        if (!connect()) {
            Slog.e(TAG, "connection failed");
            return "-1";
        }

        if (!writeCommand(cmd)) {
            /*
             * If installd died and restarted in the background (unlikely but
             * possible) we'll fail on the next write (this one). Try to
             * reconnect and write the command one more time before giving up.
             */
            Slog.e(TAG, "write command failed? reconnect!");
            if (!connect() || !writeCommand(cmd)) {
                return "-1";
            }
        }
        if (LOCAL_DEBUG) {
            Slog.i(TAG, "send: '" + cmd + "'");
        }

        final int replyLength = readReply();
        if (replyLength > 0) {
            String s = new String(buf, 0, replyLength);
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "recv: '" + s + "'");
            }
            return s;
        } else {
            if (LOCAL_DEBUG) {
                Slog.i(TAG, "fail");
            }
            return "-1";
        }
    }
 private boolean connect() {
        if (mSocket != null) {
            return true;
        }
        Slog.i(TAG, "connecting...");
        try {
            mSocket = new LocalSocket();

            LocalSocketAddress address = new LocalSocketAddress("installd",
                    LocalSocketAddress.Namespace.RESERVED);

            mSocket.connect(address);

            mIn = mSocket.getInputStream();
            mOut = mSocket.getOutputStream();
        } catch (IOException ex) {
            disconnect();
            return false;
        }
        return true;
    }

    public void disconnect() {
        Slog.i(TAG, "disconnecting...");
        IoUtils.closeQuietly(mSocket);
        IoUtils.closeQuietly(mIn);
        IoUtils.closeQuietly(mOut);

        mSocket = null;
        mIn = null;
        mOut = null;
    }


    private boolean readFully(byte[] buffer, int len) {
        try {
            Streams.readFully(mIn, buffer, 0, len);
        } catch (IOException ioe) {
            Slog.e(TAG, "read exception");
            disconnect();
            return false;
        }

        if (LOCAL_DEBUG) {
            Slog.i(TAG, "read " + len + " bytes");
        }

        return true;
    }

    private int readReply() {
        if (!readFully(buf, 2)) {
            return -1;
        }

        final int len = (((int) buf[0]) & 0xff) | ((((int) buf[1]) & 0xff) << 8);
        if ((len < 1) || (len > buf.length)) {
            Slog.e(TAG, "invalid reply length (" + len + ")");
            disconnect();
            return -1;
        }

        if (!readFully(buf, len)) {
            return -1;
        }

        return len;
    }

可见,一次 transact 过程为先 connect() 来判断是否建立 socket 连接,如果已连接则通过 writeCommand() 将命令写入 socket的 mOut 管道,等待从管道的 mIn 中 readFully() 读取应答消息。

上层 PKMS 收集完相应信息,通过 socket 交给守护进程 installd,该进程才是真正干活的进程。

 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

昵称 *