飞道的博客

Android Frameworks 包管理系统(1)PackageManagerService初始化

420人阅读  评论(0)

PackageManager功能介绍

Package Manager是Android的应用程序安装包(apk)管理器,功能如下:

  • 权限处理,对系统和应用定义的Permission和Permission Group的增加、删除、查询、检查。
  • 包处理,扫描安装、卸载APK包,查询包的UID、GID、包名、系统默认程序等信息。
  • 比较两个包的Signatures是否相同。
  • 查询Activity、Provider、Receiver、Services的信息。
  • 查询Application、Package、Resource、Shard Library、Feature信息。
  • Intent匹配

体系结构图

  • 应用层 Market安装Google Market应用、PackageInstaller.apk 是
    /packages/apps/PackageInstaller 目录下默认的apk,用于安装SD卡或内部存储设备上的APK安装包。
  • 中间层 1.PackageManger和它的子类ApplicationPackageManager ,上层通过调用该API接口实现功能
    2.ADB和pm命令,用来安装和卸载apk。最终实现都在PackageManagerService中。
  • 服务层 PackageManagerService及相关类,一些具体的功能由Settings、Installer、FileObserver、DefaultContainerService等模块实现。

PackageManager类关系图

PackageManagerService启动

//frameworks/base/services/java/com/android/server/SystemServer.java

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


private void run() {
...
startBootstrapServices()
...
}

startBootstrapServices(){
...
//mOnlyCore 系统属性加密状态, 
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
    Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
    mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
    Slog.w(TAG, "Device encrypted - only parsing core apps");
    mOnlyCore = true;
}

//mFactoryTestMode 是否工厂模式,mOnlyCore系统属性是否加密
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
        mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
}
//frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

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();
    ServiceManager.addService("package", m);
    return m;
}

在SystemService启动过程中,调用PackageManagerService的Main方法创建一个新对象,同时将该服务注册到ServiceManager中,注册名为package。
PackageManagerService初始化流程

加下来分析PackageManangerService的构造函数

1 创建并初始化Settings对象

分为两个步骤 :

  1. 创建Settings对象
  2. 增加默认共享ID
//frameworks/base/services/java/com/android/server/pm/PackageManagerService.java

//初始化Settings对象
mSettings = new Settings(mPackages);
//增加系统默认的6个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);

看下Settings的构造函数

//frameworks/base/services/java/com/android/server/pm/Settings.java

Settings(File dataDir, Object lock) {
    mLock = lock;
    mRuntimePermissionsPersistence = new RuntimePermissionPersistence(mLock);
    mSystemDir = new File(dataDir, "system");
    //创建data/system目录
    mSystemDir.mkdirs();
    FileUtils.setPermissions(mSystemDir.toString(),
            FileUtils.S_IRWXU|FileUtils.S_IRWXG
            |FileUtils.S_IROTH|FileUtils.S_IXOTH,
            -1, -1);
    //mSttingsFilename 代表 /system/data/packages.xml文件 ,记录系统中已安装apk的运行信息
    mSettingsFilename = new File(mSystemDir, "packages.xml");
    //mBackupSettingsFilename 代表 /system/data/packages-backup.xml文件,用于安装、卸载apk时,临时备份的文件
    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
    //mPackageListFilename 代表 /system/data/packages.list文件,用于记录已安装apk的简略信息
    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;

}

SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {

    // ArrayMap<String, SharedUserSetting> mSharedUsers,通过name索引
    SharedUserSetting s = mSharedUsers.get(name);
    if (s != null) {
        if (s.userId == uid) {
            return s;
        }
                //只保存第一个Uid
        PackageManagerService.reportSettingsProblem(Log.ERROR,
                "Adding duplicate shared user, keeping first: " + name);
        return null;
    }
    //SharedUserSetting 保存的是名字、UID、应用类型
    s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
    s.userId = uid;
    if (addUserIdLPw(uid, s, name)) {
        mSharedUsers.put(name, s);
        return s;
    }
    return null;
}


private boolean addUserIdLPw(int uid, Object obj, Object name) {

    Last_UID = 19999,表示应该程序最大的UID
    if (uid > Process.LAST_APPLICATION_UID) {
        return false;
    }
    FIRST_UID = 10000,表示应用程序最小UID
    if (uid >= Process.FIRST_APPLICATION_UID) {
        int N = mUserIds.size();
        //index 用UID-10000,表示数组中的位置
        final int index = uid - Process.FIRST_APPLICATION_UID;
        while (index >= N) {
            mUserIds.add(null);
            N++;
        }
        if (mUserIds.get(index) != null) {
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate user id: " + uid
                    + " name=" + name);
            return false;
        }
        //ArrayList<Object> mUserIds ,存储大于10000的UID,按顺序排列,存储对象是SharedUserSetting
        mUserIds.set(index, obj);
    } else {
        //SparseArray<Object> mOtherUserIds 存储小于10000的UID,按序排列,存储对象是SharedUserSetting
        if (mOtherUserIds.get(uid) != null) {
            PackageManagerService.reportSettingsProblem(Log.ERROR,
                    "Adding duplicate shared id: " + uid
                            + " name=" + name);
            return false;
        }
        mOtherUserIds.put(uid, obj);
    }
    return true;
}

Setting初始化类图

在AdroidManifest.xml会声明 android:sharedUserId属性,概属性和UID有关,作用如下

  1. 声明同一个UID的APK可以共享数据,运行在统一进程内。
  2. 通过声明指定的UID,如android.uid.system,应用将会运行在制定的system进程内

2 获取系统默认配置

  1. 获得系统属性
    ro.build.type 属性表示系统是eng、userdebug、user中哪个版本。如果是eng版本,不对apk文件进行dexopt操作。scanDirLI会根据该属性判断是否对APK进行obex优化。
/**debug.separate_processes 用于标记是否在独立进程中运行某个程序,
 *根据该值设置mDefParseFlags、mSeparateProcesses,用于scanDirli扫描安装APK参数配置
 */
String separateProcesses = SystemProperties.get("debug.separate_processes");
  1. 获得系统默认显示参数
//获得屏幕默认显示参数,在scanDirLi扫描安装APK时使用,主要匹配APK中的asset和resource
mMetrics = new DisplayMetrics();

3 启动PackageHandler

//启动serviceThread去处理安装请求。
mHandlerThread = new ServiceThread(TAG,Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
//PackageManagerService内部类PakcageHandler
mHandler = new PackageHandler(mHandlerThread.getLooper());

//连接 DefaultContainerService服务
private boolean connectToService() {
    //bind DefaultContainerService,PackageHandler中真正处理APK地方
    Intent service = new Intent().setComponent(DEFAULT_CONTAINER_COMPONENT);
    Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
    if (mContext.bindServiceAsUser(service, mDefContainerConn,
            Context.BIND_AUTO_CREATE, UserHandle.SYSTEM)) {
        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
        mBound = true;
        return true;
    }
    Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
    return false;
}

//通过以下消息完成APK的复制、更名
switch (msg.what) {
case INIT_COPY:
case MCS_BOUND:
case MCS_RECONNECT:
case MCS_UNBIND:
case MCS_GIVE_UP:
case SEND_PENDING_BROADCAST:
case START_CLEANING_PACKAGE:
case POST_INSTALL:
....
}

4 创建data目录并初始化UserManagerServices(多用户)

File dataDir = Environment.getDataDirectory();
//表示 /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/app-private目录
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
sUserManager = new UserManagerService(context, this,
        new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
//frameworks/base/services/java/com/android/server/pm/UserManagerServices.java

private UserManagerService(Context context, PackageManagerService pm,
        UserDataPreparer userDataPreparer, Object packagesLock, File dataDir) {
    mContext = context;
    mPm = pm;
    mPackagesLock = packagesLock;
    mHandler = new MainHandler();
    mUserDataPreparer = userDataPreparer;
    synchronized (mPackagesLock) {
        //表示 /data/system/user目录
        mUsersDir = new File(dataDir, USER_INFO_DIR);
        //创建 /data/system/user目录
        mUsersDir.mkdirs();
        // 表示 /data/system/user/0目录 用户0目录
        File userZeroDir = new File(mUsersDir, String.valueOf(UserHandle.USER_SYSTEM));
               //创建 /data/system/user/0目录  
        userZeroDir.mkdirs();
        // 表示 /data/system/user/userlist.xml文件 关于所有用户的参数
        mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
        initDefaultGuestRestrictions();
        readUserListLP();
        sInstance = this;
    }
    mLocalService = new LocalService();
    LocalServices.addService(UserManagerInternal.class, mLocalService);
    mLockPatternUtils = new LockPatternUtils(mContext);
    mUserStates.put(UserHandle.USER_SYSTEM, UserState.STATE_BOOTING);
}

private void readUserListLP() {
    // /data/system/user/userlist.xml文件是否存在
    if (!mUserListFile.exists()) {
        //创建userlist.xml文件
        fallbackToSingleUserLP();
        return;
    }
    FileInputStream fis = null;
    打开/data/system/user/userlist.xml文件,检索信息
    AtomicFile userListFile = new AtomicFile(mUserListFile);
    //读取用户ID
    String id = parser.getAttributeValue(null, ATTR_ID);
        //读取用户ID对应的 id.xml 文件,用户ID详细信息
    UserData userData = readUserLP(Integer.parseInt(id));
    //在mUsers存入对应的ID.xml信息
    mUsers.put(userData.info.id, userData);

}

private void fallbackToSingleUserLP() {
    int flags = UserInfo.FLAG_INITIALIZED;
    //创建系统用户
    UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags);
    UserData userData = putUserInfo(system);
    mNextSerialNumber = MIN_USER_ID;
    mUserVersion = USER_VERSION;

    Bundle restrictions = new Bundle();
  
    //创建 /data/system/users/用户id.xml文件,关于该用户相关的参数
    writeUserLP(userData);
    //创建 /data/system/user/userlist.xml文件 ,所有用户的参数
    writeUserListLP();
}

UserData类图

5 解析系统permission和feature信息

解析/system/etc/sysconfig 和 /system/etc/permission中的xml文件,包括platform.xml和系统支持的各种软硬件(feature)配置文件

  1. platform.xml
    该文件用于定义底层进程的UID(User ID) 和GID (Group ID)和Android 定义的权限名之间的映射关系。在该文件中,一共有四种标签。
    1.permission 2.group 3.assign-permission 4.library
    group是permission 的子标签
    assign-permission 位指定的用户ID分配指定的Android权限。
    library 指定系统扩展库,也称共享库
<permissions>
<!--给指定的GID分配指定的权限-->
<permission name="android.permission.INTERNET" >
    <group gid="inet" />
</permission>

<!--给指定UID分配权限-->
<assign-permission name="android.permission.WAKE_LOCK" uid="media" />
<assign-permission name="android.permission.UPDATE_DEVICE_STATS" uid="media" />

<!--指定系统扩展库,扩展系统功能-->
<library name="android.test.runner"
        file="/system/framework/android.test.runner.jar" />

<!--允许在省电模式下联网应用-->
<allow-in-power-save package="com.android.providers.downloads" />

<!--允许在数据模式下联网应用-->
<allow-in-data-usage-save package="com.android.providers.downloads" />

<!--在后台自由运行的应用-->
<allow-in-power-save package="com.android.shell" />

<!--作为系统用户运行的应用-->
<system-user-whitelisted-app package="com.android.settings" />

<!--不能作为系统用户运行的应用-->
<system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
  1. feature配置文件
    该文件用于设定设备支持的软硬件特性,硬件配置Hardware feature 文件 和 SoftWare feature配置文件。
  1. Hardware feature
    用于配置Audio、Bluetooth、Camera、Location、Microphone、Nfc、Sensors、Screen、Telephony、USB、Wifi,每个配置文件都以android.hardware开头。
    camera配置信息
/frameworks/native/data/etc/andorid.hardware.camera.autofocus.xml
<permissions>
    <feature name="android.hardware.camera.any" />
        <!--设备支持carmea-->
    <feature name="android.hardware.camera" />
    <!--设备支持自动对焦-->
    <feature name="android.hardware.camera.autofocus" />
    <!--设备支持闪光灯-->
    <feature name="android.hardware.camera.flash" />
</permissions>

核心硬件配置文件以_core_hardware结尾,如handheld_core_hardware.xml和tablet_core_hardware.xml。包含各个硬件的xml文件。

  1. software feature声明
    默认情况下支持SIP和VOIP两种软件特性,
    通过该配置文件决定设备使用相应特性功能和API。
/frameworks/native/data/etc/android.software.sip.voip.xml
//该配置表示设备支持SIP和基于SIP的VOIP软件特性
<permissions>
    <feature name="android.software.sip" />
    <feature name="android.software.sip.voip" />
</permissions>
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);
        ...
}

void readPermissions(File libraryDir, int permissionFlag) {
//解析各种标签
}
}

systemConfig类图

readPermissions具体解析过程
1.解析group标签,将其gid存入SystemConfid.mGlobalGids中,该标签指定所有包共有的全局GID,该标签默认未使用
2.解析permission标签,存入了ArrayMap<String, PermissionEntry> mPermissions,也存入了PackageMangerServices.mSettings.mPermissions中,以name为key值
3.解析assing-permission标签,以UID为key值,permission为value值,存入SystemConfig.mSystemPermissions中
4.解析library标签, 存入ArrayMap<String, String> mSharedLibraries SystemConfig.mSharedLibraries中,以name为key值,file文件位置为value值。
5.解析feature标签, 存入ArrayMap<String, FeatureInfo> SystemConfig.mAvailableFeatures,以name为key值,FeatureInfo(name属性和版本号)为value。
6.解析allow-in-power-save-except-idle,allow-in-power-save,allow-in-power-save…存入对应的数组

6 解析packages.xml文件

主要解析/data/system/packages.xml 文件,记录了系统的permission,已经安装apk的name、CodePath、flags、version、userid等信息。这写信息主要通过ScanDirLi方法解析APK的AndroidManifest.xml文件获取。当有apk安装、卸载时会更新该文件。
系统第一次启动时,packages.xml文件不存在,后续ScanDirLi扫描后才出现。
packages_backup.xml是 packages.xml 备份文件,每次更新packages.xml时,先将packages.xml改名为packages_backup.xml,再创建新的paclages.xml,创建成功后会删除packages_backup.xml。

mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));


boolean readLPw(@NonNull List<UserInfo> users){
if (tagName.equals("package")) {
    //解析package标签
    readPackageLPw(parser);
} else if (tagName.equals("permissions")) {
    //解析permission标签
    readPermissionsLPw(mPermissions, parser);
}.....

}


//解析 package标签。
private void readPackageLPw(XmlPullParser parser){
1.无shareUserId应用读取信息后,加入Settings.mPackages中,以包名为索引,便签内容为value。Uid>10000加入加入Settings.mUserIds中,根据UID排序。小于10000加入Settings.mOtherUserIds中,以UID排序,标签内容为value。
2.有shareUserId应用读取信息后,加入Settings.mPendingPackages中。

readLPw后续会读取mPendingPackages中的信息,将shareUserId应用ID设为shareUserId,,将share应用信息加入该应用,之后重新加入到Settings.mPackages中。
}

//解析permission标签
private void readPermissionsLPw(){
将信息存入Sttings.mPermissions中,以权限名为索引,vlaue包括包名,保护等级
}

}

7 调用scanDirLi扫描安装apk

扫描 Vendor/overlay/、/system/framework、/system/app、/system/priv-app、/vendor/app、/vendor/priv-app目录下的APK
如果是!OnlyCore还会扫描 /data/app 和/data/app-private目录。

  • 系统级安装包:Vendor/overlay/、/system/framework、/system/app、/system/priv-app、/vendor/app、/vendor/priv-app都是系统级安装包,parseFlag都包含PackageParser.PARSE_IS_SYSTEM和
    PackageParser.PARSE_IS_SYSTEM_DIR标签
  • FORWARD_LOCK安装包:/data/app-private,parseFlag包含PackageParser.PARSE_FORWARD_LOCK标签,会做DRM保护处理,apk文件会存于/data/app-private目录,该目录受系统保护,一般apk在data/app下。该安装包会在/data/app目录下生成一个.zip包。zip中只有apk的res目录,AndroidManifest.xml和resources.arsc文件。无其他文件。起到保护apk资源目的
  • 普通安装包:在data/app下,不给parseFlags传参数。

同时还会传递scanFlags,其中有SCAN_NO_DEX 即不进行dexopt优化。
后续详细分析 scanDirLi方法过程。

//扫描Vendor/overlay/目录
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM
        | PackageParser.PARSE_IS_SYSTEM_DIR
        | PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);

//扫描/system/framework 目录
scanDirTracedLI(frameworkDir, mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM
        | PackageParser.PARSE_IS_SYSTEM_DIR
        | PackageParser.PARSE_IS_PRIVILEGED,
        scanFlags | SCAN_NO_DEX, 0);

//扫描/system/priv-app 目录
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);

//扫描 /system/app 目录
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
scanDirTracedLI(systemAppDir, mDefParseFlags
        | PackageParser.PARSE_IS_SYSTEM
        | PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);

//非只加载核心模块
if (!mOnlyCore) {
    //扫描data/app目录
    scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
    //扫描/data/app-private目录
    scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
            | PackageParser.PARSE_FORWARD_LOCK,
            scanFlags | SCAN_REQUIRE_KNOWN, 0);
    ...
}

8 更新packages.xml文件

将更新信息写入到/data/system/packages.xml ,该文件就是mSettings中存储信息的持久化。

  1. 将存在的packages.xml改名为packages_backup.xml,将mSettings中信息写入packages.xml,写入完成后删除
    packages_backup.xml文件
  2. 创建packages.list文件,遍历mPackages,写入包名、UID、文件位置,简略版的packages.xml。
mSettings.writeLPr();

mPermission -> <permission>标签
mPackages -> <package>标签

PMS初始化结束…END
重点方法scanDirLi后续分析。

参考资料


转载:https://blog.csdn.net/jinao8004/article/details/104735440
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场