Android PakageManagerService源码解析

2019-01-02  本文已影响13人  孤独的根号十二

PakageManagerService

PakageManagerService是android系统中一个核心的服务,它负责系统中Package的管理,应该程序的安装、卸载等。
SystemServer进程是Zygote孵化出的第一个进程,该进程主要的工作是启动android系统服务进程,其中包括PackageManagerService服务

SystemServer:run()

    try {
            startBootstrapServices();
            startCoreServices();
            startOtherServices();
        } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        }

启动PakageManagerService

private void startBootstrapServices() {
        //...
         //调用PMS的main函数
         mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
         //判断本次是否为初次启动,当Zygote或者SystemServer退出时,init会再次启动它们,所以这里
         //的firstBoot指的是开机后的第一次启动
        mFirstBoot = mPackageManagerService.isFirstBoot();
        mPackageManager = mSystemContext.getPackageManager();
      //...
    } 

PakageManagerService的main()

//扫描Android系统中几个目标文件夹的APK,建立对应的数据结构来管理Package信息、四大组件信息、权限信息等各种信息
public static PackageManagerService main(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        //new 一个PackageManagerService对象
        PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
        //PKM注册到ServiceManager上。ServiceManager相当于安卓系统服务的DNS服务器
        ServiceManager.addService("package", m);
        return m;
 }

PakageManagerService的构造方法

public PackageManagerService(Context context, Installer installer,
            boolean factoryTest, boolean onlyCore) {
        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
                SystemClock.uptimeMillis());

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

        mContext = context;   //ActivityThread getSystemContext()
        mFactoryTest = factoryTest;  // //是否在工厂测试模式下,假定为false
        mOnlyCore = onlyCore;
        mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type")); //如果此系统是“eng”版,扫描Package后,不对package做dex优化
        mMetrics = new DisplayMetrics();
        //第一个参数是字符串“android.uid.system”;第二个是SYSTEM_UID,其值为1000,
        //第三个是FLAG_SYSTEM标志,用于标识系统Package。
        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);
        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);

Settings 与在manifest注册android:sharedUserId="android.uid.system"有关
在该标签中,声明了一个android:sharedUserId的属性,其值为“android.uid.system”。sharedUserId和UID有关,它的作用是

两个或者多个声明了同一种sharedUserid的APK可共享彼此的数据,并且可运行在同一进程中。
通过声明特定的sharedUserId,该APK所在的进程将被赋予指定UID。
例如SystemUI声明了system的uid,运行SystemUI的进程就可享有system用户所对应的权限了,实际上就是将该进程的UID设置为system的uid了


..........................................省略部分代码...............................................

  // 获取系统相关的权限,它主要是解析系统目录下xml文件,获得设备相关的权限

  SystemConfig systemConfig = SystemConfig.getInstance();
 mGlobalGids = systemConfig.getGlobalGids();
 mSystemPermissions = systemConfig.getSystemPermissions();
  mAvailableFeatures = systemConfig.getAvailableFeatures();
 synchronized (mInstallLock) {
// writer
  synchronized (mPackages) {
//创建一个ThreadHandler对象,实际就是创建一个带消息队列循环处理的线程,
  //该线程的工作是:程序的安装和卸载等。
 mHandlerThread = new ServiceThread(TAG,
  Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
  mHandlerThread.start();

 //以ThreadHandler线程的消息循环(Looper对象)作为参数new一个

  //PackageHandler,因此该Handler的handlemessage方法将运行在此线程上

 mHandler = new PackageHandler(mHandlerThread.getLooper());

 Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);

 // /data目录

  File dataDir = Environment.getDataDirectory();

// /data/data目录
  mAppDataDir = new File(dataDir, "data");
  // /data/app目录
  mAppInstallDir = new File(dataDir, "app");
  // /data/app-lib目录
  mAppLib32InstallDir = new File(dataDir, "app-lib");
 // /data/app-asec目录
  mAsecInternalPath = new File(dataDir, "app-asec").getPath();

  // /data/user目录
  mUserAppDataDir = new File(dataDir, "user");

  // /data/app-private目录
  mDrmAppPrivateInstallDir = new File(dataDir, "app-private");

 //new一个UserManager对象,目前没有什么作用,但其前途[不可限量](https://www.baidu.com/s?wd=%E4%B8%8D%E5%8F%AF%E9%99%90%E9%87%8F&tn=24004469_oem_dg&rsv_dl=gh_pl_sl_csd)。

  //google设想,未来手机将支持多个User,每个User安装自己的应用

 //该功能为android智能手机推向企业用户打下基础

 sUserManager = new UserManagerService(context, this,

 mInstallLock, mPackages);

  // 获取系统相关的权限,它主要是解析系统目录下xml文件,获得设备相关的权限

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

 }

 }

  //获得系统的Libraries,也就是系统的一些jar

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

  }
  mFoundPolicyFile = SELinuxMMAC.readInstallPolicy();

  mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),

 mSdkVersion, mOnlyCore);

  String customResolverActivity = Resources.getSystem().getString(

  R.string.config_customResolverActivity);

 if (TextUtils.isEmpty(customResolverActivity)) {

customResolverActivity = null;

 } else {

  mCustomResolverComponentName = ComponentName.unflattenFromString(

customResolverActivity);

  }
long startTime = SystemClock.uptimeMillis();

             /**
             * Ensure all external libraries have had dexopt run on them.
             *扫描优化各种系统库,主要是扫描系统中的APK,由于需要逐个扫描apk文件,因此手机上安装的程序越多,PKM的工作量越大,系统启动速度越慢,也就是开机时间越长。
             */
            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 {
                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                alreadyDexOpted.add(lib);
                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Library not found: " + lib);
                        } catch (IOException e) {
                            Slog.w(TAG, "Cannot dexopt " + lib + "; is it an APK or JAR? "
                                    + e.getMessage());
                        }
                    }
                }
            }

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

            // Gross hack for now: we know this file doesn't contain any
            // code, so don't dexopt it to avoid the resulting log spew.
            alreadyDexOpted.add(frameworkDir.getPath() + "/framework-res.apk");

            // Gross hack for now: we know this file is only part of
            // the boot class path for art, so don't dexopt it to
            // avoid the resulting log spew.
            alreadyDexOpted.add(frameworkDir.getPath() + "/core-libart.jar");

            /**
             * There are a number of commands implemented in Java, which
             * we currently need to do the dexopt on so that they can be
             * run from a non-root shell.
             */
            String[] frameworkFiles = frameworkDir.list();
            if (frameworkFiles != null) {
                // TODO: We could compile these only for the most preferred ABI. We should
                // first double check that the dex files for these commands are not referenced
                // by other system apps.
                for (String dexCodeInstructionSet : dexCodeInstructionSets) {
                    for (int i=0; i<frameworkFiles.length; i++) {
                        File libPath = new File(frameworkDir, frameworkFiles[i]);
                        String path = libPath.getPath();
                        // Skip the file if we already did it.
                        if (alreadyDexOpted.contains(path)) {
                            continue;
                        }
                        // Skip the file if it is not a type we want to dexopt.
                        if (!path.endsWith(".apk") && !path.endsWith(".jar")) {
                            continue;
                        }
                        try {
                            int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
                            if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                    //dex优化
                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded);
                            }
                        } catch (FileNotFoundException e) {
                            Slog.w(TAG, "Jar not found: " + path);
                        } catch (IOException e) {
                            Slog.w(TAG, "Exception reading jar: " + path, e);
                        }
                    }
                }
            }

       //下面代码就是扫描系统app和厂商默认的app,还有已经安装的app

             // 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.
            File vendorOverlayDir = new File(VENDOR_OVERLAY_DIR);
            scanDirLI(vendorOverlayDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

            // Find base frameworks (resource packages without code).
            scanDirLI(frameworkDir, 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");
            scanDirLI(privilegedAppDir, 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");
            scanDirLI(systemAppDir, 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
            }
            scanDirLI(vendorAppDir, PackageParser.PARSE_IS_SYSTEM
                    | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

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


解析每个app的manifest文件,添加4大组件

 private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg, int parseFlags,
            int scanFlags, long currentTime, UserHandle user) throws PackageManagerException {
//省略部分代码
     N = pkg.activities.size();
            r = null;
            for (i=0; i<N; i++){
                PackageParser.Activity a = pkg.activities.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mActivities.addActivity(a, "activity");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }


......................................

 N = pkg.receivers.size();
            r = null;
            for (i=0; i<N; i++) {
                PackageParser.Activity a = pkg.receivers.get(i);
                a.info.processName = fixProcessName(pkg.applicationInfo.processName,
                        a.info.processName, pkg.applicationInfo.uid);
                mReceivers.addActivity(a, "receiver");
                if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                    if (r == null) {
                        r = new StringBuilder(256);
                    } else {
                        r.append(' ');
                    }
                    r.append(a.info.name);
                }
            }
.........................................
}

5.4扫描系统和非系统apk总结

PKM在这个过程中工作任务非常繁重,要创建很多的对象,所以它是一个耗时耗内存的操作,从流程来看,PKM在这个过程中无非是扫描XML或者APK文件,但是其中涉及的数据结构及它们的关系较为复杂。

上一篇 下一篇

猜你喜欢

热点阅读