Android4.4 PackageManagerService详细分析

一、systemserver中建立 installer 与 installd 的 socket 联接

// Wait for installdto finished starting up so that it has a chance to

// create criticaldirectories such as /data/user with the appropriate

// permissions.  We need this to complete before we initializeother services.

Slog.i(TAG,”Waiting for installd to be ready.”);

installer = new Installer();

installer.ping();

 

二、systemserver中创建PackageManagerService

pm =PackageManagerService.main(context, installer,

factoryTest!= SystemServer.FACTORY_TEST_OFF, onlyCore);

这里讲installer作为参数传入

 

三、在PackageManagerService.main中主要功能是构造PackageManagerService 实例,然后添加到 ServiceManager 中。

public static finalIPackageManager main(Context context, boolean factoryTest) {

       PackageManagerService m = new PackageManagerService(context, factoryTest);

       ServiceManager.addService(“package”, m);

       return m;

    }

 

四、PackageManagerService(context, factoryTest) 是 包 管 理服 务 的 主 进 程 。 它 完 成 了对/system/app,/data/app,/system/framework,/data/app-private下的 apk 文件的解析。详细流程如下: 

mContext = context;

mFactoryTest =factoryTest;

mOnlyCore =onlyCore;

mNoDexOpt= “eng”.equals(SystemProperties.get(“ro.build.type”));//判断 ro.build.type 是否等于 eng;

mMetrics = new DisplayMetrics();//创建系统显示像素实例

mSettings = new Settings(context);//创建mSetting实例

mSettings.addSharedUserLPw(“android.uid.system”,Process.SYSTEM_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

mSettings.addSharedUserLPw(“android.uid.phone”,RADIO_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

mSettings.addSharedUserLPw(“android.uid.log”,LOG_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

mSettings.addSharedUserLPw(“android.uid.nfc”,NFC_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

mSettings.addSharedUserLPw(“android.uid.bluetooth”,BLUETOOTH_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

mSettings.addSharedUserLPw(“android.uid.shell”,SHELL_UID,

ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED);

 

这个settings是在frameworks/base/services/java/com/android/server/pm/目录下,和系统设置并非同一样东西

Settings(Contextcontext, File dataDir) {

mContext= context;

mSystemDir= new File(dataDir, “system”);

mSystemDir.mkdirs();

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,0660, SYSTEM_UID, PACKAGE_INFO_GID);

 

//Deprecated: Needed for migration

mStoppedPackagesFilename= new File(mSystemDir, “packages-stopped.xml”);

mBackupStoppedPackagesFilename= new File(mSystemDir, “packages-stopped-backup.xml”);

}

 

回到第四步中创建完了Settings实例,紧接着就添加了一系列的权限完成了

 

 

五、获取当前缺省的显示像素

WindowManagerwm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);

                 Display d = wm.getDefaultDisplay();

                 d.getMetrics(mMetrics);

 

 

六、建立一个消息循环,用于处理 apk 安装时的请求消息处理(这些请求来自 adbinstall/push,包安装器,android market 下载安装 apk 时发送的)

mHandlerThread.start();

    mHandler = newPackageHandler(mHandlerThread.getLooper());

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

这个消息循环处理的消息事件如下:

   static final int SEND_PENDING_BROADCAST = 1;

   static final int MCS_BOUND = 3;

   static final int END_COPY = 4;

   static final int INIT_COPY = 5;

   static final int MCS_UNBIND = 6;

   static final int START_CLEANING_PACKAGE = 7;

   static final int FIND_INSTALL_LOC = 8;

   static final int POST_INSTALL = 9;

   static final int MCS_RECONNECT = 10;

   static final int MCS_GIVE_UP = 11;

   static final int UPDATED_MEDIA_STATUS = 12;

   static final int WRITE_SETTINGS = 13;

 

 

七、创建/data/data 和/data/app-private等目录

File dataDir =Environment.getDataDirectory();

mAppDataDir = newFile(dataDir, “data”);

mAppInstallDir = newFile(dataDir, “app”);

mAppLibInstallDir =new File(dataDir, “app-lib”);

mAsecInternalPath =new File(dataDir, “app-asec”).getPath();

mUserAppDataDir =new File(dataDir, “user”);

mDrmAppPrivateInstallDir= new File(dataDir, “app-private”);

 

sUserManager = newUserManagerService(context, this,

        mInstallLock, mPackages);

 

 

八、从/system/etc/permission目录读取 permissions

readPermissions();

readPermissions函数中的具体步骤

VoidreadPermissions()

{

      //解析/system/etc/permission/下的*.xml 文件,获取权限信息

      //最后解析该目录下的 platform.xml 文件,使该文件里的权限在栈顶出现,以便预先处理

      //这个文件记录了系统级应用的 uid 及其拥有的权限

       File permFile = newFile(Environment.getRootDirectory(),”etc/permissions/platform.xml”);

       readPermissionsFromXml(permFile);

}

注:getRootDirectory返回的是/system目录

DIR_ANDROID_ROOT =getDirectory(ENV_ANDROID_ROOT, “/system”);

public static FilegetRootDirectory() {

   return DIR_ANDROID_ROOT;

}

readPermissionsFromXml函数的功能如下:  

通过 xml 解 析 器 解 释 *.xml 文 件 , 提 取 标 签 名 “ group” , “permission” ,”assign-permission”,”library”,”feature”并进行相应处理。在platform.xml 中对底层的系统用户和组ID(group ids)同上层的由平台管理的 permission 名字之间进行了关系映射,使它们关联起来。当一个应用被授予某个权限后,同时属于已知的组 ID,这个应用就可以进行允许这个组的文件系统操作,如(read,write,execute )。这里记录了一些系统级的应用的 uid 对应的permission

 

group:安装到系统中的所有 APK都具备的组 ID。

permission:可以指定一个权限与几个组ID 对应。当一个 APK 被授予这个权限时,它也同时属于这几个组。

assign-permission:把一个权限赋予一个UID,当进程使用这个 UID 运行时,就具备了这个权限。

library:为系统添加一些扩展库用的。对应的.jar文件放在/system/framework/目录下。比如Google Map 相关的库。

feature : 每 添 加 一 个硬 件 , 都 要 增 加 对 应 的 feature 。 将 以 上 解 析 的 结 果 对 应 放 入

 

九、readLPw()

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

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

判断/data/system/packages.xml文件是否存在,如果不存在则返回 false,如果存在则进行解析

在系统第一次启动时packages.xml 文件是不存在的,由 writeLP()创建该文件,并将该文件写到 nand 上,下次开机会直接读取并解析这个文件。

解析的过程即是按照xml定义的标签,将对应的属性和值添加到全局列表中。packages.xml 文件中记录了系统安装的所有 apk 的属性权限的信息,当系统中的 apk安装,删除或升级时,改文件就会被更新。

<permissions>标签定义了目前系统中定义的所有权限。主要分为两类: 系 统 定 义 的(package 属性为 Android)和 APK 定义的(package 属性为 APK 的包名)

sharedUserId/userId:Android系统启动一个普通的 APK 时,会为这个 APK 分配一个独立的UID , 这 就 是 userId 。 如 果 APK 要 和 系 统 中 其 它 APK使 用 相 同 的 UID 的 话 , 那 就 是sharedUserId。

perms:APK的 AndroidManifest.xml 文件中,每使用一个<uses-permission>标签,<perms>标签中就会增加一项。

<shared-user>代表一个共享UID , 通 常 , 共 同 实 现 一 系 列 相 似 功 能 的 APK 共 享 一 个UID。<perms>标签中的 权限代表了这个共享 UID 的权限,所有使用的同一个共享 UID 的APK 运行在同一进程中,这个进程的 UID 就是这个共享 UID,这些 APK 都具有这个共享UID 的权限。

name:共享 UID 的名字,在APK 的 Android:sharedUserId 属性中使用。

userId:使用这个共享 UID的所有 APK 运行时所在的进程的 UID。

 

 

十、判断是否使用了自定义的intentresolver

StringcustomResolverActivity = Resources.getSystem().getString(

       R.string.config_customResolverActivity);  //这个属性配置在frameworks/base/core/res/res/values/config.xml中

if(TextUtils.isEmpty(customResolverActivity)) {

    customResolverActivity =null;//如果配置文件中为空

} else {

    mCustomResolverComponentName =ComponentName.unflattenFromString(

            customResolverActivity);

}

 

十一、是否需要做dexopt

需要做dexopt一共有以下几类:

  1. 所有在java.boot.class.path中的内容都被默认为在zygote阶段已经做过dexopt,所以当前阶段跳过
  1. 所有external libraries必须做dexopt
  1. 所有的/framework下的apk和jar都需要做dexopt,但是跳过framework-res.apk和core-libart.jar

 

十二、启 动AppDirObserver 线 程

主要 监 测/system/framework , /system/priv-app, /system/app , /vendor/app,/data/app,/data/app-private 几个目录的事件 ,AppDirObserver继承于FileObserverFileObserver中有一些native方法,从而达到监听底层文件状态变化的event,这里主要监听的是 add 和 remove 事件。对于目录监听底层通过 inotify机制实现,inotify 是在 2.6.13中引入的新功能,它为用户态监视文件系统的变化提供了强大的支持;inotify 是一种文件系统的变化通知机制,如文件增加 ,删除等事件可以立刻让用户态得知

mFrameworkInstallObserver= new AppDirObserver(frameworkDir.getPath(),OBSERVER_EVENTS, true, false);

mFrameworkInstallObserver.startWatching();

scanDirLI(frameworkDir, PackageParser.PARSE_IS_SYSTEM

        | PackageParser.PARSE_IS_SYSTEM_DIR

        | PackageParser.PARSE_IS_PRIVILEGED,

        scanMode | SCAN_NO_DEX, 0);

当监测到事件发生时该线程做何处理呢?

 

 

十二、清理系统packages

清理策略如下:

mSettings.mPackages.values().iterator();是当前package的全集

1.  不是系统app,跳过不予处理

if ((ps.pkgFlags& ApplicationInfo.FLAG_SYSTEM) == 0) {

     continue;

}

2.如果package存在mPackages中,且不是isDisabledSystemPackageLPr,不予处理

if ((ps.pkgFlags& ApplicationInfo.FLAG_SYSTEM) == 0) {

    continue;

}

 

3.如果package存在mPackages中,且是isDisabledSystemPackageLPr,说明是OTA加进来的,需要删除

finalPackageParser.Package scannedPkg = mPackages.get(ps.name);

if (scannedPkg !=null) {

if(mSettings.isDisabledSystemPackageLPr(ps.name)) {

    Slog.i(TAG, “Expecting better updatdsystem app for ” + ps.name+ “; removing system app”);

    removePackageLI(ps, true);

}

continue;

}

4.既不在mPackages中,也不是isDisabledSystemPackageLPr,说明这个package已经不存在了,删除

5.不在mPackages中,但是isDisabledSystemPackageLPr,加入到possiblyDeletedUpdatedSystemApps中

if(!mSettings.isDisabledSystemPackageLPr(ps.name)) {

psit.remove();

Stringmsg = “System package ” + ps.name+ ” no longer exists; wipingits data”;

    reportSettingsProblem(Log.WARN, msg);

    removeDataDirsLI(ps.name);

} else {

    final PackageSetting disabledPs =mSettings.getDisabledSystemPkgLPr(ps.name);

    if (disabledPs.codePath == null ||!disabledPs.codePath.exists()) {

       possiblyDeletedUpdatedSystemApps.add(ps.name);

  }

}

 

十三、清除不完整的、临时的包等

//look for anyincomplete package installations

ArrayList<PackageSetting>deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();

//clean up list

for(int i = 0; i< deletePkgsList.size(); i++) {

//cleanup here

   cleanupInstallFailedPackage(deletePkgsList.get(i));

}

 

//delete tmp files

deleteTempPackageFiles();

 

// Remove any shareduserIDs that have no associated packages

mSettings.pruneSharedUsersLPw();

 

十四、在解析完以上目录下的 apk 后,更新应用的权限

updatePermissionsLPw(null,null, UPDATE_PERMISSIONS_ALL | (regrantPermissions

       ?(UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL): 0));

 

十五、生成/更新packages.xml  和 packages.list 文 件

mSettings.writeLPr();

 

以上是包管理服务在系统启动时做的全部工作。

 

 

 

 

 

    原文作者:konan1027
    原文地址: https://blog.csdn.net/konan1027/article/details/25721397
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞