源码分析 — PackageManagerService(一)之启动流程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Love667767/article/details/79595237

一、概述

  1. 背景

    本文主要分析PackageManagerService 的初始化过程;

  2. 版本

    系统 版本
    Android 23
  3. PackageManagerService 的启动流程:

    Zygote --> SystemServer --> PackageManagerService(PMS)

  4. 关于SystemServer的启动,请参考:
    源码分析 — SystemServer启动

二、PMS初始化时序图

这里写图片描述

三、PMS源码

  • SystemServer
public static void main(String[] args) {
   new SystemServer().run();
}

private void run() {
    // ...省略大段代码...
    startBootstrapServices();
}

private void startBootstrapServices() {
     /* 
      * 创建ActivityManagerService实例
      * 注意:mActivityManagerService是被添加进SystemServiceManager维护起来的
      */
     mActivityManagerService = mSystemServiceManager.startService(
             ActivityManagerService.Lifecycle.class).getService();

     /*
      * 创建PackageManagerService实例;
      * 注意:PackageManagerService没有被SystemServiceManager维护起来;
      * 思考:那它到底被谁维护起来了呢?
      */
     mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
             mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);     
}
  • PackageManagerService
public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
    // Self-check for initial settings.
    PackageManagerServiceCompilerMapping.checkProperties();

    PackageManagerService m = new PackageManagerService(context, installer,
            factoryTest, onlyCore);
    m.enableSystemUserPackages();

    // 在这里将PackageManagerService实例添加到ServiceManager中
    ServiceManager.addService("package", m);
    return m;
}

小结:

  1. PackageManagerService 实例是被ServiceManager 存储起来;
  2. ActivityManagerService 实例是被SystemServiceManager 存储起来;

PackageManagerService 构造方法内主要执行以下几件事:

  1. 创建Settings 对象,其内部创建了packages.xml、packages-backup.xml、packages.list 等文件,用于存储应用信息;
  2. SystemConfig 对象中,读取系统配置来初始化 mGlobalGids、mSystemPermissions、mAvailableFeatures
  3. 指定 /data 目录下的一些列的文件夹目录,如/data/data、/data/app 等;
  4. 如果packages.xml 文件存在,则读取并解析该文件信息,然后保存到Settings相应的字段中;
  5. 开始扫描指定目录下的apk文件,解析其Manifest文件,并将值赋值给Package对应的属性字段(这个步骤是重点);
  6. 更新所有的共享库;
  7. 更新应用权限;
  8. 将数据写入packages.xml中;
/*
 * 该方法主要的作用:
 * 
 * 扫描指定文件路径下的文件:
 * 1.vendorOverlayDir = "/vendor/overlay"
 * 2.frameworkDir = "/system/framework"
 * 3.privilegedAppDir = "/system/priv-app"
 * 4.systemAppDir = "/system/app"
 * 5.vendorAppDir = "/vendor/app"
 * 6.mAppInstallDir = "/data/app"
 * 7.mDrmAppPrivateInstallDir = "/data/app-private"
 */
public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {

    // ...代码省略...

    // 1.添加SharedUserSetting对象到mSettings中。  
    mSettings = new Settings(mPackages);
    mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID, ...);
    mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ...);
    mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ...);
    mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ...);
    mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ...);
    mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ...);

    // ...代码省略...

    // 2.读取系统配置来初始化mGlobalGids、mSystemPermissions、mAvailableFeatures
    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();
            mHandler = new PackageHandler(mHandlerThread.getLooper());

            /* 
             * 3.指定 "/data" 目录下的文件夹,便于使用;
             * dataDir = "/data"
             * mAppDataDir = "/data/data" 应用数据存储目录
             * mAppInstallDir = "/data/app" 应用安装目录
             * mAppLib32InstallDir = "/data/app-lib" 
             * mAsecInternalPath = "/data/app-asec"
             * mUserAppDataDir = "/data/user"
             * mDrmAppPrivateInstallDir = "/data/app-private"
             */ 
            File dataDir = Environment.getDataDirectory();
            mAppDataDir = new File(dataDir, "data");
            mAppInstallDir = new File(dataDir, "app");
            mAppLib32InstallDir = new File(dataDir, "app-lib");
            mAsecInternalPath = new File(dataDir, "app-asec").getPath();
            mUserAppDataDir = new File(dataDir, "user");
            mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

            // 4.从packages.xml文件中解析出信息(如果该文件存在),并保存到Settings相应的字段中;
            mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
                    mSdkVersion, mOnlyCore);

            // ...省略大段代码...

            // 5.使用scanDirLI()扫描指定目录下的apk文件,解析其Manifest文件,并将值赋值给Package对应的属性字段;
            // vendorOverlayDir = "/vendor/overlay"
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            // scanDirLI()是重点;
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

            /* 
             * Find base frameworks (resource packages without code).
             * frameworkDir = "/system/framework"
             * framework包里都是jar包和apk
             */
            File frameworkDir = new File(Environment.getRootDirectory(), "framework");
            scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR
                    | PackageParser.PARSE_IS_PRIVILEGED,
                    scanFlags | SCAN_NO_DEX, 0);

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

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

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

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


            // mOnlyCore = true表示系统package
            if (!mOnlyCore) {
                // 这里扫描用户应用:mAppInstallDir = "/data/app"
                scanDirLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
                // 这里扫描用户应用:mDrmAppPrivateInstallDir = "/data/app-private"
                scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,
                        scanFlags | SCAN_REQUIRE_KNOWN, 0);

                // ...省略大段代码...
            }

            // ...省略大段代码...

            // Now that we know all of the shared libraries, update all clients to have the correct library paths.
            //6.更新所有的共享库;
            updateAllSharedLibrariesLPw();

            // ...省略代码...
            // 7.更新应用权限;
            updatePermissionsLPw(null, null, updateFlags);
            // ...省略代码...

            // 8.将数据写入packages.xml中;
            mSettings.writeLPr();
        } // synchronized (mPackages)
    } // synchronized (mInstallLock)

    // ...省略代码...
}

下面着重分析第 1、4、5、8 点;

3.1 Settings类

Settings(Context context) {
    this(context, Environment.getDataDirectory());
}

/*
 * 在 "/data/system/" 目录下创建一系列的文件;
 */
Settings(File dataDir, Object lock) {
    // 创建一个"/system"目录
    mSystemDir = new File(dataDir, "system");
    mSystemDir.mkdirs();

    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);

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

小结:

所在目录: /data/system/

文件 含义
packages.xml 记录系统中所有安装的应用信息,包括基本信息、签名和权限
packages-backup.xml packages.xml 文件的备份
packages.list 保存普通应用的数据目录和uid等信息
packages-stopped.xml 记录系统中被强制停止运行的应用信息。
packages-stopped-backup.xml pacakges-stopped.xml 文件的备份
  • Settings.addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags)
ArrayMap<String, SharedUserSetting> mSharedUsers = new ArrayMap<String, SharedUserSetting>();

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
    SharedUserSetting s = mSharedUsers.get(name);
    // ...代码省略...
    s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
    s.userId = uid;
    if (addUserIdLPw(uid, s, name)) {
        // 将SharedUserSetting添加到mSharedUsers中;
        mSharedUsers.put(name, s);
        return s;
    }
    return null;
}

3.2 packages.xml 等文件的读取及解析

/*
 * 本方法实际就是对packages.xml、packages-backup.xml等文件进行操作,从中获取到对应的值;
 */
boolean readLPw(PackageManagerService service, List<UserInfo> users, 
        int sdkVersion, boolean onlyCore) {
    FileInputStream str = null;
    // 如果packages-backup.xml存在,则解析备份文件;
    if (mBackupSettingsFilename.exists()) {
        str = new FileInputStream(mBackupSettingsFilename);
        // ...代码省略...
        if (mSettingsFilename.exists()) {
            mSettingsFilename.delete();
        }
    }
    // ...代码省略...

    //  如果packages-backup.xml不存在,则解析packages.xml
    if (str == null) {
        if (!mSettingsFilename.exists()) {
            return false;
        }
        str = new FileInputStream(mSettingsFilename);
    }
    XmlPullParser parser = Xml.newPullParser();
    parser.setInput(str, StandardCharsets.UTF_8.name());

    // ...代码省略...

    int type;
    int outerDepth = parser.getDepth();
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        // 接下去就是xml文件解析
        String tagName = parser.getName();
        if (tagName.equals("package")) {
            readPackageLPw(parser);
        } else if (tagName.equals("permissions")) {
            readPermissionsLPw(mPermissions, parser);
        }
        // ...省略很多xml节点解析代码...
    }
    str.close();

    // ...代码省略...

    if (mBackupStoppedPackagesFilename.exists()
            || mStoppedPackagesFilename.exists()) {
        // 这个方法的逻辑和readLPw()方法类似,只是这里读取的是packages-stopped.xml和packages-stopped-backup.xml文件;
        readStoppedLPw();
        mBackupStoppedPackagesFilename.delete();
        mStoppedPackagesFilename.delete();
        // Migrate to new file format
        writePackageRestrictionsLPr(0);
    } else {
        // ...代码省略...
    }
    // ...代码省略...
    return true;
}

3.3 Manifest 文件的解析

扫描指定目录下的apk文件,解析其Manifest文件,并将值赋值给Package对应的属性字段(这个步骤是重点);

  • PackageManagerService.scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime)
/*
 * 扫描指定的文件夹,如果是该文件夹内的文件是apk文件或是文件夹,则继续扫描;
 */
private void scanDirLI(File dir, int parseFlags, int scanFlags, long currentTime) {
    final File[] files = dir.listFiles();
    if (ArrayUtils.isEmpty(files)) return;

    for (File file : files) {
        // isApkFile(file):文件后缀是否为apk
        final boolean isPackage = (isApkFile(file) || file.isDirectory())
                && !PackageInstallerService.isStageName(file.getName());
        if (!isPackage) {// 如果是常规文件(非文件夹、非Apk文件),则跳过;
            continue;
        }
        // 扫描指定的文件目录或apk
        scanPackageLI(file, parseFlags | PackageParser.PARSE_MUST_BE_APK,
                    scanFlags, currentTime, null);
    }
}

/*
*  解析Apk包中的Manifest.xml文件
* 
 * 返回的PackageParser.Package对象,表示一个Apk文件对应的数据结构;
 */
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanFlags,
                                            long currentTime, UserHandle user) throws PackageManagerException {
    PackageParser pp = new PackageParser();

    // 解析Apk包中的清单文件,将对应节点设置到Package对应的属性字段上;
    final PackageParser.Package pkg = pp.parsePackage(scanFile, parseFlags);

    // ...省略大段代码...

    // Verify certificates against what was last scanned.
    // 对安装的程序进行签名验证(这里不展开)
    collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);

    // ...省略大段代码...

    // Note that we invoke the following method only if we are about to unpack an application
    PackageParser.Package scannedPkg = scanPackageLI(pkg, parseFlags, scanFlags
            | SCAN_UPDATE_SIGNATURE, currentTime, user);

    // ...省略代码...
    return scannedPkg;
}
  • PackageParser

    主要功能就是解析Apk文件中的 Manifest.xml 文件

/*
 * `parseClusterPackage()、parseMonolithicPackage()`
 *  这两个方法内部都会执行parseBaseApk();
 */
public Package parsePackage(File packageFile, int flags) throws PackageParserException {
    if (packageFile.isDirectory()) {//packageFile是文件夹
        return parseClusterPackage(packageFile, flags);
    } else {//packageFile是Apk文件
        return parseMonolithicPackage(packageFile, flags);
    }
}

/*
 * 解析Apk文件
 */
public Package parseMonolithicPackage(File apkFile, int flags) throws PackageParserException {
    // ...代码省略...
    final Package pkg = parseBaseApk(apkFile, assets, flags);
    // ...代码省略...
    return pkg;
}

private Package parseClusterPackage(File packageDir, int flags) throws PackageParserException {
    final PackageLite lite = parseClusterPackageLite(packageDir, 0);
    final AssetManager assets = new AssetManager();
    try {
        final File baseApk = new File(lite.baseCodePath);
        // 返回一个Package对象,该对象包含了Manifest文件中的所有节点信息;
        final Package pkg = parseBaseApk(baseApk, assets, flags);
        // ...代码省略...
        if (!ArrayUtils.isEmpty(lite.splitNames)) {
            final int num = lite.splitNames.length;
            // ...代码省略...
            for (int i = 0; i < num; i++) {
                // 这个方法和上面的parseBaseApk()执行逻辑类似,不再重复;
                parseSplitApk(pkg, i, assets, flags);
            }
        }
        return pkg;
    } finally {
        IoUtils.closeQuietly(assets);
    }
}

/*
 * 解析BaseApk的清单文件,并返回一个Package对象;
 */
private Package parseBaseApk(File apkFile, AssetManager assets, int flags)
            throws PackageParserException {
    final String apkPath = apkFile.getAbsolutePath();
    // ...代码省略...

    Resources res = null;
    XmlResourceParser parser = null;
    try {
        res = new Resources(assets, mMetrics, null);
        assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                Build.VERSION.RESOURCES_SDK_INT);
        // 解析 ANDROID_MANIFEST_FILENAME 文件
        parser = assets.openXmlResourceParser(cookie, ANDROID_MANIFEST_FILENAME);

        // 解析Manifest文件下的所有节点,将他们存储到Package对应的字段中,并返回Package对象;
        final Package pkg = parseBaseApk(res, parser, flags, outError);
        // ...代码省略...
        return pkg;
    } catch (Exception e) {
        // ...代码省略...
    }
}

/*
 * 解析Manifest文件下的所有节点,将他们存储到Package对应的字段中,并返回Package对象;
 */
private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
            String[] outError) throws XmlPullParserException, IOException {
    final boolean trustedOverlay = (flags & PARSE_TRUSTED_OVERLAY) != 0;
    // ...代码省略... 

    // 创建一个Package对象,用于存储从Manifest文件中解析出来的节点信息;
    final Package pkg = new Package(pkgName);  

    // ...代码省略...   
    int outerDepth = parser.getDepth();
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
            continue;
        }

        if (tagName.equals("application")) {
            // 解析Manifest文件中application节点之间的所有节点信息;
            if (!parseBaseApplication(pkg, res, parser, attrs, flags, outError)) {
                return null;
            }
        } else if (tagName.equals("uses-permission")) {
            // 解析Manifest文件中uses-permission节点信息,并将它存储到Package.requestedPermissions字段中;
            if (!parseUsesPermission(pkg, res, parser, attrs)) {
                return null;
            }
        }
        // ...省略大段代码... 
    }
    // ...省略大段代码... 
    return pkg;
}

/**
 * 解析manifest文件中Application节点下的节点,将对应的节点分别保存在Package对象的对应字段属性中;
 * 
 * 如四大组件标签存放的字段:
 * List<Activity> activities;
 * List<Activity> receivers;
 * List<Provider> providers;
 * List<Service> services;
 */
private boolean parseBaseApplication(Package owner, Resources res,
        XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
    throws XmlPullParserException, IOException {

    // ...省略大段代码...

    // 开始解析
    final int innerDepth = parser.getDepth();
    int type;
    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
            && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) {
        // ...省略代码...

        String tagName = parser.getName();
        if (tagName.equals("activity")) {
            // 解析Manifest文件中的Activity节点
            Activity a = parseActivity(owner, res, parser, attrs,
                flags, outError, false, owner.baseHardwareAccelerated);
            // ...省略代码...
            // 将该Activity添加到Packagearser.Package.activities中;
            owner.activities.add(a);

        } else if (tagName.equals("receiver")) {
            // 将该Receiver添加到Packagearser.Package.receivers中;
            owner.receivers.add(a);

        } else if (tagName.equals("service")) {
            // 将该Service添加到Packagearser.Package.services中;
            owner.services.add(s);

        } else if (tagName.equals("provider")) {
            // 将该Provider添加到Packagearser.Package.providers中;
            owner.providers.add(p);
        } 
        // ...省略大段代码...
    }
    // ...省略代码...
    return true;
}

小结:
到这里,这个Apk文件的Manifest.xml文件的解析就结束了;


  • PackageManagerService.scanPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags, long currentTime, UserHandle user)

这个方法的目的:
1. 主要是将Package的值赋值给PMS中对应的属性字段,一遍在外部操作PMS时,可以很容易获取到所需的数据;
2. 将PackageParser.Package对象中的值存入到Setting中;

private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags,
                                            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
    boolean success = false;
    try {
        final PackageParser.Package res = scanPackageDirtyLI(pkg, parseFlags, scanFlags,
                currentTime, user);
        success = true;
        return res;
    } finally {
        if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
            removeDataDirsLI(pkg.volumeUuid, pkg.packageName);
        }
    }
}

/*
 * 1.将PackageParser.Package对象中的值赋值给PackageSetting对象中,然后将PackageSetting对象存入到Setting.mPackages中;
 * 2.将PackageParser.Package对象中的值,赋值非PackageManagerService对应的字段中;
 */ 
private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
                                                     int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {                                            
    // framework-res.apk的包名是android
    if (pkg.packageName.equals("android")) {
        // ...代码省略...
    }
    // ...代码省略...

    // writer
    synchronized (mPackages) {
        // ...省略大段代码...

        // Just create the setting, don't add it yet. For already existing packages
        // the PkgSetting exists already and doesn't have to be created.
        pkgSetting = mSettings.getPackageLPw(pkg, origPackage, realName, suid, destCodeFile,
                destResourceFile, pkg.applicationInfo.nativeLibraryRootDir,
                pkg.applicationInfo.primaryCpuAbi,
                pkg.applicationInfo.secondaryCpuAbi,
                pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags,
                user, false);

        // ...省略大段代码...    
    }
    // ...省略大段代码... 

    // writer
    synchronized (mPackages) {
        // ...代码省略...

        /*
         * 类似的赋值有:四大组件:
         * ProviderIntentResolver mProviders;
         * ServiceIntentResolver mServices;
         * ReceiverIntentResolver mReceivers;
         * ActivityIntentResolver mActivitys;
         * 
         * 其他:
         * ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation instrumentation;
         * ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups permissionGroups、
         */ 
        int N = pkg.providers.size();
        for (int i = 0; i < N; i++) {
            PackageParser.Provider p = pkg.providers.get(i);
            /* 
             * 将PackageParse.Package中的字段赋值给PackageManagerService中对应的字段;
             * 其实真正的值存储在PackageManagerService.ProviderIntentResolver.mProviders字段中;
             * 
             * ProviderIntentResolver.mProviders字段存储了整个系统的provider;
             */
            mProviders.addProvider(p);   
            // ...代码省略...        
        }       
        // ...代码省略...
    }
    return pkg;
}
  • Settings.getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
    String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
    String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
    int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add)
PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage,
            String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
            String legacyNativeLibraryPathString, String primaryCpuAbi, String secondaryCpuAbi,
            int pkgFlags, int pkgPrivateFlags, UserHandle user, boolean add) {

    final String name = pkg.packageName;
    PackageSetting p = getPackageLPw(name, origPackage, realName, sharedUser, codePath,
            resourcePath, legacyNativeLibraryPathString, primaryCpuAbi, secondaryCpuAbi,
            pkg.mVersionCode, pkgFlags, pkgPrivateFlags, user, add, true /* allowInstall */);
    return p;
}

/*
 * 主要是值的转换:将Package装换为PackageSetting,并将PackageSetting添加到Settings.mPackages字段中;
 */
private PackageSetting getPackageLPw(String name, PackageSetting origPackage,
            String realName, SharedUserSetting sharedUser, File codePath, File resourcePath,
            String legacyNativeLibraryPathString, String primaryCpuAbiString,
            String secondaryCpuAbiString, int vc, int pkgFlags, int pkgPrivateFlags,
            UserHandle installUser, boolean add, boolean allowInstall) {
    // 根据包名获取到这个包的PackageSetting信息;
    PackageSetting p = mPackages.get(name);
    UserManagerService userManager = UserManagerService.getInstance();
    if (p != null) {
        // 根据条件对p的一些属性进行赋值;
    }
    if (p == null) {
        // 代码有略微改写:其大意为:如果对象PackageSetting=null,就创建一个PackageSetting,并将Package的值赋值给他,然后将PackageSetting对象添加到Settings.mPackages字段中;
        p = new PackageSetting(name, realName, codePath, resourcePath,
                legacyNativeLibraryPathString, primaryCpuAbiString, secondaryCpuAbiString,
                null /* cpuAbiOverrideString */, vc, pkgFlags, pkgPrivateFlags);
        // 将pkg中的属性和其他的属性赋值给p;

        if (add) {// 将PackageSetting对象保存在Settings.mPackages字段中;
            addPackageSettingLPw(p, name, sharedUser);
        }
    } else {
        // ...代码省略...
    }
    return p;
}

private void addPackageSettingLPw(PackageSetting p, String name,
            SharedUserSetting sharedUser) {          
    // 将PackageSetting对象保存在Settings.mPackages字段中;
    mPackages.put(name, p);

    // ...代码省略...
}

3.4 将数据写入packages.xml中

void writeLPr() {
    /*
     * 前提:packages.xml存在
     * 1.备份不存在,就将packages.xml重命名成备份名;
     * 2.备份存在,就删除packages.xml文件;
     * 总结:只要有一份文件即可;
     */
    if (mSettingsFilename.exists()) {
        if (!mBackupSettingsFilename.exists()) {
            if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
                return;
            }
        } else {
            mSettingsFilename.delete();
        }
    }
    // 开始向packages.xml文件中写入应用相关的数据;
    try {
        FileOutputStream fstr = new FileOutputStream(mSettingsFilename);
        BufferedOutputStream str = new BufferedOutputStream(fstr);

        //XmlSerializer serializer = XmlUtils.serializerInstance();
        XmlSerializer serializer = new FastXmlSerializer();
        serializer.setOutput(str, StandardCharsets.UTF_8.name());
        serializer.startDocument(null, true);
        serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
        serializer.startTag(null, "packages");

        // ...省略很多节点插入的代码...

        // 写入权限
        serializer.startTag(null, "permissions");
        for (BasePermission bp : mPermissions.values()) {
            writePermissionLPr(serializer, bp);
        }
        serializer.endTag(null, "permissions");

        // 将Package数据写入
        for (final PackageSetting pkg : mPackages.values()) { 
            writePackageLPr(serializer, pkg);
        }
        // ...省略很多节点插入的代码...

        serializer.endTag(null, "packages");
        serializer.endDocument();

        str.flush();
        FileUtils.sync(fstr);
        str.close();

        // 到这里,packages.xml已经写入了最新的数据,所以需要删除packages-backup.xml文件
        mBackupSettingsFilename.delete();
        // 设置packages.xml文件的权限;
        FileUtils.setPermissions(mSettingsFilename.toString(),
                FileUtils.S_IRUSR|FileUtils.S_IWUSR
                |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
                -1, -1);

        // 向packages.list文件中写入数据
        writePackageListLPr();
        writeAllUsersPackageRestrictionsLPr();
        writeAllRuntimePermissionsLPr();
        return;

    } catch(Exception e) {
        //...
    }
    // Clean up partially written files
    if (mSettingsFilename.exists()) {
        if (!mSettingsFilename.delete()) {
            //...
        }
    }
}

四、总结

  1. "/data/system" 目录中创建一系列的文件用于存储应用的信息;
  2. SystemConfig 对象中读取系统配置来初始化 mGlobalGids、mSystemPermissions、mAvailableFeatures
  3. 指定 "/data" 目录下一些文件夹`,一部分是用于第4步的扫描目录的指定;
  4. 读取 packages.xml 文件的数据,解析并存储到Settings中;
  5. 扫描指定文件目录下的Apk包,解析其内部的Manifest.xml文件,将值赋值给PMS和Settings、Package中;
  6. 将扫描出来的应用信息重新写入第4步的 packages.xml 文件中;

五、参考

  1. PackageManagerService源码分析之第一阶段(二)
阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页