Android服务之PackageManagerService启动源码分析

了解了Android系统的启动过程的读者应该知道,Android的所有Java服务都是通过SystemServer进程启动的,并且驻留在SystemServer进程中。SystemServer进程在启动时,通过创建一个ServerThread线程来启动所有服务,本文主要介绍Android服务中PackageManagerService服务启动过程。首先介绍一些PackageManagerService服务下的相关类关系图:

 

在SystemServer进程的ServerThread线程中,执行以下代码启动PackageManagerService服务:


// 通过读取属性来判断运行核心应用

String cryptState = SystemProperties.get("vold.decrypt");

boolean onlyCore = false;

if (ENCRYPTING_STATE.equals(cryptState)) {

    Slog.w(TAG, "Detected encryption in progress - only parsing core apps");

    onlyCore = true;

} else if (ENCRYPTED_STATE.equals(cryptState)) {

    Slog.w(TAG, "Device encrypted - only parsing core apps");

    onlyCore = true;

}

//启动PackageManagerService

pm = PackageManagerService.main(context,

        factoryTest != SystemServer.FACTORY_TEST_OFF,

        onlyCore);

boolean firstBoot = false;

//判断PackageManagerService是否是第一次启动,SystemServer进程被杀后会被重启

try {

    firstBoot = pm.isFirstBoot();

} catch (RemoteException e) {

}

//PackageManagerService执行dex优化

...

try {

    pm.performBootDexOpt();

} catch (Throwable e) {

    reportWtf("performing boot dexopt", e);

}
首先启动PackageManagerService,然后判断该服务是否是第一次启动,接着执行dex优化。


public static final IPackageManager main(Context context, boolean factoryTest,

        boolean onlyCore) {

    //构造PackageManagerService服务对象

    PackageManagerService m = new PackageManagerService(context, factoryTest, onlyCore);

    //注册PackageManagerService服务

    ServiceManager.addService("package", m);

    return m;

}
启动过程比较简单,就是构造一个PackageManagerService对象,然后将该服务对象注册到ServiceManger进程中,关于服务注册过程请查看Android服务注册完整过程源码分析。PackageManagerService对象构造过程非常复杂,构造过程分几个阶段.


//PackageManagerService启动开始

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());

//SDK版本检查

if (mSdkVersion <= 0) {

    Slog.w(TAG, "**** ro.build.version.sdk not set!");

}

//读取开机启动模式

String mode = SystemProperties.get("ro.bootmode", "mode");

engModeEnable = "engtest".equals(mode)?true:false;

Slog.i(TAG, "engModeEnable: " + engModeEnable + " ,mode:"+mode);

mContext = context;

mFactoryTest = factoryTest;//开机模式

mOnlyCore = onlyCore;//是否对包做dex优化

//如果编译版本为eng,则不需要dex优化

mNoDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));

//创建显示尺寸信息

mMetrics = new DisplayMetrics();

//存储系统运行过程中的设置信息

mSettings = new Settings();

/*创建SharedUserSetting对象并添加到Settings的成员变量mSharedUsers中,在Android系统中,多个package通过设置sharedUserId属性可以运行在同一个进程,共享同一个UID*/

mSettings.addSharedUserLPw("android.uid.system",Process.SYSTEM_UID, ApplicationInfo.FLAG_SYSTEM);

mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID, ApplicationInfo.FLAG_SYSTEM);

mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);

mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);

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;

}

mPreInstallDir = new File("/system/preloadapp");

//创建应用安装器

mInstaller = new Installer();

//获取屏幕尺寸大小

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

Display d = wm.getDefaultDisplay();

d.getMetrics(mMetrics);

synchronized (mInstallLock) {

// writer

synchronized (mPackages) {

    //启动消息处理线程

    mHandlerThread.start();

    //为消息处理线程创建一个消息分发handler

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

    // dataDir =/data/

    File dataDir = Environment.getDataDirectory();

    // mAppDataDir = /data/data

    mAppDataDir = new File(dataDir, "data");

    // mAsecInternalPath = /data/app-asec

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

    // mUserAppDataDir = /data/user

    mUserAppDataDir = new File(dataDir, "user");

    // mDrmAppPrivateInstallDir = /data/app-private

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

    sUserManager = new UserManager(mInstaller, mUserAppDataDir);

    //读取并解析/etc/permissions下的XML文件

    readPermissions();

    mRestoredSettings = mSettings.readLPw(getUsers());
函数首先创建一个Settings对象,用来保存一些设置信息,然后调用addSharedUserLPw向Settings类的成员变量mSharedUsers中添加SharedUserSetting对象,在Android系统中,通过设置android:sharedUserId="android.uid.system"属性可以为应用程序指定UID,SharedUserSetting对象保存同一共享进程UID的所有包信息,Settings对象用于管理Android系统运行过程中的一些设置信息,Settings的成员变量mSharedUsers以键值对的方式保存UID对应的SharedUserSetting对象。在Android系统中,可以通过在AndroidManifest.xml文件中设置sharedUserId属性来设置多个APK运行在同一个进程中。PackageManagerService的任务就是构造一些数据结构来保存所有APK的配置信息,关于Settings类之间的关系图如下:

PackageSignatures来用来描述Android应用程序安装包的签名信息,GrantedPermissions类用于描述应用APK的权限信息。Settings类的成员变量mSharedUsers是一个HashMap,用键值对的形式保存所有的SharedUserSetting对象,SharedUserSetting对象用于记录共享同一进程的所有APK信息,该类的成员变量packages的类型为PackageSetting,用来保存所有共享同一UID的包信息,而成员变量userId则是记录多个APK共享的UID。首先介绍Settings对象的构造过程:


Settings() {

    //调用另外一个有参构造函数

    this(Environment.getDataDirectory());

}

 

Settings(File dataDir) {

    //创建/data/system/目录

    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=/data/system/packages.xml

    mSettingsFilename = new File(mSystemDir, "packages.xml");

    //mBackupSettingsFilename=/data/system/packages-backup.xml

    mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");

    //mPackageListFilename=/data/system/packages.list

    mPackageListFilename = new File(mSystemDir, "packages.list");

    // Deprecated: Needed for migration

    //mStoppedPackagesFilename = /data/system/packages-stopped.xml

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

    //mStoppedPackagesFilename = /data/system/packages-stopped-backup.xml

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

}
 

Settings对象的构造过程很简单,就是创建一些目录和文件。首先创建/data/system/目录,然后分别创建以下四个文件:
/data/system/packages.xml
/data/system/packages-backup.xml
/data/system/packages.list
/data/system/packages-stopped.xml
/data/system/packages-stopped-backup.xml
Settings通过addSharedUserLPw函数添加向mSharedUsers预先添加SharedUserSetting对象
 


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

    //根据进程UID对应的名称从成员变量mSharedUsers中查找对应的SharedUserSetting对象

    SharedUserSetting s = mSharedUsers.get(name);

    //返回查找到的结果

    if (s != null) {

        if (s.userId == uid) {

            return s;

        }

        PackageManagerService.reportSettingsProblem(Log.ERROR,

                "Adding duplicate shared user, keeping first: " + name);

        return null;

    }

    //没有查找到对应的SharedUserSetting对象,则创建一个新的SharedUserSetting对象。

    s = new SharedUserSetting(name, pkgFlags);

    s.userId = uid;

    //添加到成员变量mUserIds,mOtherUserIds中,这两个变量主要是加快查找速度

    if (addUserIdLPw(uid, s, name)) {

        //添加到mSharedUsers表中

        mSharedUsers.put(name, s);

        return s;

    }

    return null;

}
 

函数首先根据字符串名称从成员变量mSharedUsers哈希表中查找对应的SharedUserSetting对象,如果表中不存在对应的SharedUserSetting对象,则创建一个新的SharedUserSetting对象,并初始化该对象的域,然后根据UID的大小通过函数addUserIdLPw添加到mUserIds或mOtherUserIds中,同时以键值对的形式保存在mSharedUsers中。
 


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

    //判断添加的UID是否大于19999

    if (uid > Process.LAST_APPLICATION_UID) {

        return false;

    }

    //判断添加的UID是否大于等于10000

    if (uid >= Process.FIRST_APPLICATION_UID) {

        //计算在数组中的索引为uid-10000

        int N = mUserIds.size();

        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;

        }

        //添加的SharedUserSetting对象到mUserIds动态数组中

        mUserIds.set(index, obj);

    } else {//将UID小于1000,则将SharedUserSetting对象添加到mOtherUserIds数组中

        if (mOtherUserIds.get(uid) != null) {

            PackageManagerService.reportSettingsProblem(Log.ERROR,

                    "Adding duplicate shared id: " + uid

                    + " name=" + name);

            return false;

        }

        mOtherUserIds.put(uid, obj);

    }

    return true;

}
 

Android定义了应用程序的UID范围,对于非系统应用,UID介于1000到1999之间,而对于系统应用,UID小于1000


public static final int SYSTEM_UID = 1000;

public static final int PHONE_UID = 1001;

public static final int SHELL_UID = 2000;

public static final int LOG_UID = 1007;

public static final int WIFI_UID = 1010;

public static final int MEDIA_UID = 1013;

public static final int DRM_UID = 1019;

public static final int SDCARD_RW_GID = 1015;

public static final int VPN_UID = 1016;

public static final int NFC_UID = 1027;

public static final int MEDIA_RW_GID = 1023;

//应用程序UID范围

public static final int FIRST_APPLICATION_UID = 10000;

public static final int LAST_APPLICATION_UID = 19999;

//fully isolated sandboxed processes UID范围

public static final int FIRST_ISOLATED_UID = 99000;

public static final int LAST_ISOLATED_UID = 99999;
 

addUserIdLPw函数将UID介于1000到1999之间的SharedUserSetting对象添加到mUserIds数组中,通过UID来索引数组元素。

UID小于1000的SharedUserSetting保存到数组mOtherUserIds中。回到PackageManagerService的构造函数中,通过Settings的addSharedUserLPw函数向mSharedUsers,mUserIds,mOtherUserIds数组添加了4个特定进程的SharedUserSetting对象。
 


mPreInstallDir = new File("/system/preloadapp");

//创建应用安装器

mInstaller = new Installer();

//获取屏幕尺寸大小

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

Display d = wm.getDefaultDisplay();

d.getMetrics(mMetrics);

synchronized (mInstallLock) {

// writer

synchronized (mPackages) {

    //启动消息处理线程

    mHandlerThread.start();

    //为消息处理线程创建一个消息分发handler

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

    // dataDir =/data/

    File dataDir = Environment.getDataDirectory();

    // mAppDataDir = /data/data

    mAppDataDir = new File(dataDir, "data");

    // mAsecInternalPath = /data/app-asec

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

    // mUserAppDataDir = /data/user

    mUserAppDataDir = new File(dataDir, "user");

    // mDrmAppPrivateInstallDir = /data/app-private

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


mPreInstallDir = new File("/system/preloadapp");

//创建应用安装器

mInstaller = new Installer();

//获取屏幕尺寸大小

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

Display d = wm.getDefaultDisplay();

d.getMetrics(mMetrics);

synchronized (mInstallLock) {

// writer

synchronized (mPackages) {

    //启动消息处理线程

    mHandlerThread.start();

    //为消息处理线程创建一个消息分发handler

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

    // dataDir =/data/

    File dataDir = Environment.getDataDirectory();

    // mAppDataDir = /data/data

    mAppDataDir = new File(dataDir, "data");

    // mAsecInternalPath = /data/app-asec

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

    // mUserAppDataDir = /data/user

    mUserAppDataDir = new File(dataDir, "user");

    // mDrmAppPrivateInstallDir = /data/app-private

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

首先创建Installer对象,用于访问installd服务进程,完成一些apk安装,卸载,优化工作。然后通过WindowManager得到屏幕尺寸信息,接着启动一个名为PackageManager的消息线程,该线程是PackageManagerService的工作线程,mHandlerThread线程是一个带消息循环的工作线程,在定义该线程对象的时候就已经创建
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",Process.THREAD_PRIORITY_BACKGROUND);

同时为该消息线程创建了一个消息分发器PackageHandler对象,通过该handler对象可以往PackageManager线程发送消息,PackageManager线程通过消息循环处理发送进来的消息,消息处理过程如下:


public void handleMessage(Message msg) {

    try {

        //直接调用doHandleMessage函数来处理各种消息

        doHandleMessage(msg);

    } finally {

        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

    }

}
 

这里暂时不介绍doHandleMessage函数,在介绍特定消息时,在来分析该函数对各种消息的处理过程。PackageManagerService的线程模型如下:

最后就是创建一些安装目录:
/system/preloadapp
/data/data
/data/app-asec
/data/user
/data/data
/data/app-private
创建用户管理对象UserManager:

sUserManager = new UserManager(mInstaller, mUserAppDataDir);
 

构造了一个UserManager,参数一为应用程序安装器Installer,参数二为用户安装目录/data/user


public UserManager(Installer installer, File baseUserPath) {

    this(Environment.getDataDirectory(), baseUserPath);

    mInstaller = installer;

}

 

UserManager(File dataDir, File baseUserPath) {

    // mUsersDir=/data/system/users

    mUsersDir = new File(dataDir, USER_INFO_DIR);

    mUsersDir.mkdirs();

    // userZeroDir=/data/system/users/0

    File userZeroDir = new File(mUsersDir, "0");

    userZeroDir.mkdirs();

    //mBaseUserPath=/data/user

    mBaseUserPath = baseUserPath;

    FileUtils.setPermissions(mUsersDir.toString(),

                   FileUtils.S_IRWXU|FileUtils.S_IRWXG

            |FileUtils.S_IROTH|FileUtils.S_IXOTH,

            -1, -1);

    // mUserListFile=/data/system/users/userlist.xml

    mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);

    readUserList();

}
 

构造过程比较简单,就是创建几个目录和几个文件:
/data/system/users
/data/system/users/0
/data/system/users/userlist.xml
然后通过函数readUserList读取用户列表,这里不在介绍该函数的实现,该函数就是从userlist.xml文件中读取用户信息,保存到UserManager的成员变量mUsers中。
读取权限配置信息://读取并解析/etc/permissions下的XML文件readPermissions();
函数首先调用readPermissions扫描读取并解析/etc/permissions文件夹下的XML文件,并将解析的数据保存到PackageManagerService的成员变量中
 


void readPermissions() {

    // Read permissions from .../etc/permission directory.

    File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");

    if (!libraryDir.exists() || !libraryDir.isDirectory()) {

        Slog.w(TAG, "No directory " + libraryDir + ", skipping");

        return;

    }

    if (!libraryDir.canRead()) {

        Slog.w(TAG, "Directory " + libraryDir + " cannot be read");

        return;

    }

    // 循环读取etc/permissions目录下的XML文件

    for (File f : libraryDir.listFiles()) {

        // 跳过platform.xml文件,最后读取该文件

        if (f.getPath().endsWith("etc/permissions/platform.xml")) {

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

    }

    // Read permissions from .../etc/permissions/platform.xml last so it will take precedence

    final File permFile = new File(Environment.getRootDirectory(),"etc/permissions/platform.xml");

    readPermissionsFromXml(permFile);

}
 

在etc/permissions目录下保存了一下配置文件

这些文件在编译的时候直接从frameworks指定目录下拷贝过来的,在特定product编译目录下的base.mk文件中的配置如下:

函数readPermissionsFromXml使用PULL方式解析这些XML文件,下面分别介绍各个标签的解析过程。

feature标签用来描述设备应该支持的硬件特性。解析过程如下:


else if ("feature".equals(name)) {

    //读取熟悉name的值

    String fname = parser.getAttributeValue(null, "name");

    if (fname == null) {

        Slog.w(TAG, "<feature> without name at "+ parser.getPositionDescription());

    } else {

        //创建一个FeatureInfo对象

        FeatureInfo fi = new FeatureInfo();

        fi.name = fname;

        //mAvailableFeatures是PackageManagerService的成员变量,以HashMap的方式保存硬件支持的特性

        mAvailableFeatures.put(fname, fi);

    }

    XmlUtils.skipCurrentTag(parser);

    continue;

}
 


else if ("feature".equals(name)) {

    //读取熟悉name的值

    String fname = parser.getAttributeValue(null, "name");

    if (fname == null) {

        Slog.w(TAG, "<feature> without name at "+ parser.getPositionDescription());

    } else {

        //创建一个FeatureInfo对象

        FeatureInfo fi = new FeatureInfo();

        fi.name = fname;

        //mAvailableFeatures是PackageManagerService的成员变量,以HashMap的方式保存硬件支持的特性

        mAvailableFeatures.put(fname, fi);

    }

    XmlUtils.skipCurrentTag(parser);

    continue;

}

library用于指定系统库,当应用程序运行时,系统会为进程加载一些必要库。该标签的解析过程如下:


else if ("library".equals(name)) {

    //读取属性name的值

    String lname = parser.getAttributeValue(null, "name");

    //读取属性file的值

    String lfile = parser.getAttributeValue(null, "file");

    if (lname == null) {

        Slog.w(TAG, "<library> without name at "+ parser.getPositionDescription());

    } else if (lfile == null) {

        Slog.w(TAG, "<library> without file at "+ parser.getPositionDescription());

    } else {

        //mSharedLibraries是PackageManagerService的成员变量,以HashMap的形式保存进程运行库

        mSharedLibraries.put(lname, lfile);

    }

    XmlUtils.skipCurrentTag(parser);

    continue;

}
 


else if ("library".equals(name)) {

    //读取属性name的值

    String lname = parser.getAttributeValue(null, "name");

    //读取属性file的值

    String lfile = parser.getAttributeValue(null, "file");

    if (lname == null) {

        Slog.w(TAG, "<library> without name at "+ parser.getPositionDescription());

    } else if (lfile == null) {

        Slog.w(TAG, "<library> without file at "+ parser.getPositionDescription());

    } else {

        //mSharedLibraries是PackageManagerService的成员变量,以HashMap的形式保存进程运行库

        mSharedLibraries.put(lname, lfile);

    }

    XmlUtils.skipCurrentTag(parser);

    continue;

}
 

group标签用于建立Android层与Linux层之间的权限映射关系。


else if ("permission".equals(name)) {

    //读取属性name的值

    String perm = parser.getAttributeValue(null, "name");

    if (perm == null) {

        Slog.w(TAG, "<permission> without name at "+ parser.getPositionDescription());

        XmlUtils.skipCurrentTag(parser);

        continue;

    }

    perm = perm.intern();

    readPermission(parser, perm);

 

void readPermission(XmlPullParser parser, String name)

        throws IOException, XmlPullParserException {

    name = name.intern();

    //根据name在mSettings.mPermissions表中查找对应的BasePermission对象

    BasePermission bp = mSettings.mPermissions.get(name);

    //如果不存在,则创建一个新的BasePermission对象,并保存到mSettings.mPermissions中

    if (bp == null) {

        bp = new BasePermission(name, null, BasePermission.TYPE_BUILTIN);

        mSettings.mPermissions.put(name, bp);

    }

    int outerDepth = parser.getDepth();

    int type;

    while ((type=parser.next()) != XmlPullParser.END_DOCUMENT

           && (type != XmlPullParser.END_TAG

                   || parser.getDepth() > outerDepth)) {

        if (type == XmlPullParser.END_TAG

                || type == XmlPullParser.TEXT) {

            continue;

        }

        String tagName = parser.getName();

        //读取标签group的属性gid值

        if ("group".equals(tagName)) {

            String gidStr = parser.getAttributeValue(null, "gid");

            if (gidStr != null) {

                //根据gid字符串,找到对应的gid数值

                int gid = Process.getGidForName(gidStr);

                //设置BasePermission对象的gid值

                bp.gids = appendInt(bp.gids, gid);

            } else {

                Slog.w(TAG, "<group> without gid at "+ parser.getPositionDescription());

            }

        }

        XmlUtils.skipCurrentTag(parser);

    }

}
 

assign-permission标签将解析到的内容保存到mSettings.mPermissions中


else if ("assign-permission".equals(name)) {

     //读取属性name的值

    String perm = parser.getAttributeValue(null, "name");

    if (perm == null) {

        Slog.w(TAG, "<assign-permission> without name at "+ parser.getPositionDescription());

        XmlUtils.skipCurrentTag(parser);

        continue;

    }

    //读取属性uid的值

    String uidStr = parser.getAttributeValue(null, "uid");

    if (uidStr == null) {

        Slog.w(TAG, "<assign-permission> without uid at "+ parser.getPositionDescription());

        XmlUtils.skipCurrentTag(parser);

        continue;

    }

    //根据属性uid字符串转换为uid数值

    int uid = Process.getUidForName(uidStr);

    if (uid < 0) {

        Slog.w(TAG, "<assign-permission> with unknown uid \""+ uidStr + "\" at "+ parser.getPositionDescription());

        XmlUtils.skipCurrentTag(parser);

        continue;

    }

    //保存到mSystemPermissions表中

    perm = perm.intern();

    HashSet<String> perms = mSystemPermissions.get(uid);

    if (perms == null) {

        perms = new HashSet<String>();

        mSystemPermissions.put(uid, perms);

    }

    perms.add(perm);

    XmlUtils.skipCurrentTag(parser);


 

 

读取安装包信息
/data/system/packages.xml文件用于记录系统中所安装的Package信息;/data/system/packages-backup.xml文件是/data/packages.xml文件的备份。在PackageManagerService扫描完目标文件夹后会创建该文件,当系统进行程序安装卸载时会更新该文件。
/data/system/packages-stopped.xml文件用于记录系统中强制停止运行的Package信息。/data/system/packages-stopped-backup.xml是/data/packages-stopped.xml文件的备份。在强制停止某个应用时,会将应用相关信息记录到该文件中。
/data/system/packages.list保存系统中存在的所有非系统自带的APK信息,即UID大于1000的apk。
 

当系统第一次开机时,这些文件并不存在,而在以后的开机中,扫描到的这些XML文件是上一次运行过程中创建的。


boolean readLPw(List<UserInfo> users) {

    FileInputStream str = null;

    //如果/data/system/packages-backup.xml文件存在

    if (mBackupSettingsFilename.exists()) {

        try {

            //读取/data/system/packages-backup.xml文件

            str = new FileInputStream(mBackupSettingsFilename);

            mReadMessages.append("Reading from backup settings file\n");

            PackageManagerService.reportSettingsProblem(Log.INFO,"Need to read from backup settings file");

            //当/data/system/packages.xml文件的备份文件存在时,删除packages.xml文件

            if (mSettingsFilename.exists()) {

                Slog.w(PackageManagerService.TAG, "Cleaning up settings file "+ mSettingsFilename);

                mSettingsFilename.delete();

            }

        } catch (java.io.IOException e) {

            // We'll try for the normal settings file.

        }

    }

    mPendingPackages.clear();

    mPastSignatures.clear();

    try {

        //如果/data/system/packages-backup.xml文件为空

        if (str == null) {

            //同时/data/system/packages.xml文件不存在

            if (!mSettingsFilename.exists()) {

                mReadMessages.append("No settings file found\n");

                PackageManagerService.reportSettingsProblem(Log.INFO,

                        "No settings file; creating initial state");

                //读取/etc/preferred-apps目录下的xml文件

                readDefaultPreferredAppsLPw();

                return false;

            }

            //如果packages.xml的备份文件为空,读取packages.xml文件内容

            str = new FileInputStream(mSettingsFilename);

        }

        //解析文件内容

        XmlPullParser parser = Xml.newPullParser();

        parser.setInput(str, null);

        int type;

        while ((type = parser.next()) != XmlPullParser.START_TAG

                && type != XmlPullParser.END_DOCUMENT) {

            ;

        }

        ...

}
 

接下来检测并优化BOOTCLASSPATH环境变量指定的Java运行库及platform.xml中配置的Java库,同时优化/system/framework目录下的Jar包和apk文件,最后删除/data/dalvik-cache目录下的一些缓存文件。在init.rc中配置的BOOTCLASSPATH如下:
 

 


long startTime = SystemClock.uptimeMillis();

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,startTime);

// 设置扫描模式

int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING;

if (mNoDexOpt) {

    Slog.w(TAG, "Running ENG build: no pre-dexopt!");

    scanMode |= SCAN_NO_DEX;

}

//保存库文件路径

final HashSet<String> libFiles = new HashSet<String>();

//mFrameworkDir = /framework/

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

//mDalvikCacheDir = /data/dalvik-cache/

mDalvikCacheDir = new File(dataDir, "dalvik-cache");

boolean didDexOpt = false;

//通过属性的方式得到启动Java启动类库的路径,在init.rc中通过BOOTCLASSPATH环境变量的方式设置

String bootClassPath = System.getProperty("java.boot.class.path");

if (bootClassPath != null) {

    String[] paths = splitString(bootClassPath, ':');

    for (int i=0; i<paths.length; i++) {

        try {

            //判断Jar包是否需要dex优化

            if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {

                //如果需要则添加到libFiles表中

                libFiles.add(paths[i]);

                //通过安装器请求installd服务进程执行dex优化

                mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);

                didDexOpt = true;

            }

        } catch (FileNotFoundException e) {

            Slog.w(TAG, "Boot class path not found: " + paths[i]);

        } catch (IOException e) {

            Slog.w(TAG, "Cannot dexopt " + paths[i] + "; is it an APK or JAR? "

                    + e.getMessage());

        }

    }

} else {

    Slog.w(TAG, "No BOOTCLASSPATH found!");

}

//在前面解析platfor.xml时,将一些额外的类库路径保存到了mSharedLibraries变量中

if (mSharedLibraries.size() > 0) {

    //循环变量mSharedLibraries变量

    Iterator<String> libs = mSharedLibraries.values().iterator();

    while (libs.hasNext()) {

        String lib = libs.next();

        try {

            //判断Jar包是否需要dex优化

            if (dalvik.system.DexFile.isDexOptNeeded(lib)) {

                //如果需要则添加到libFiles表中

                libFiles.add(lib);

                //通过安装器进行dex优化

                mInstaller.dexopt(lib, Process.SYSTEM_UID, true);

                didDexOpt = true;

            }

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

        }

    }

}

//将/system/frameworks/framework-res.apk添加到libFiles中

libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");

//列出/system/frameworks目录下的文件

String[] frameworkFiles = mFrameworkDir.list();

if (frameworkFiles != null) {

    //遍历/system/frameworks目录下的文件

    for (int i=0; i<frameworkFiles.length; i++) {

        File libPath = new File(mFrameworkDir, frameworkFiles[i]);

        String path = libPath.getPath();

        //判断libFiles中是否已经包含该文件,如果包含则跳过

        if (libFiles.contains(path)) {

            continue;

        }

        //跳过不是apk或jar文件

        if (!path.endsWith(".apk") && !path.endsWith(".jar")) {

            continue;

        }

        try {

            //判断Jar包或apk是否需要dex优化

            if (dalvik.system.DexFile.isDexOptNeeded(path)) {

                //通过安装器进行dex优化

                mInstaller.dexopt(path, Process.SYSTEM_UID, true);

                didDexOpt = true;

            }

        } catch (FileNotFoundException e) {

            Slog.w(TAG, "Jar not found: " + path);

        } catch (IOException e) {

            Slog.w(TAG, "Exception reading jar: " + path, e);

        }

    }

}

//如果前面对某个文件做过优化,只要优化了,didDexOpt就被设置为true

if (didDexOpt) {

    //遍历/data/dalvik-cache目录下的文件

    String[] files = mDalvikCacheDir.list();

    if (files != null) {

        for (int i=0; i<files.length; i++) {

            String fn = files[i];

            //删除文件名以"data@app@"和"data@app-private@"开头的文件

            if (fn.startsWith("data@app@")

                    || fn.startsWith("data@app-private@")) {

                Slog.i(TAG, "Pruning dalvik file: " + fn);

                (new File(mDalvikCacheDir, fn)).delete();

            }

        }

    }

}
 

接着扫描系统apk信息


mFlagInstall = false;

//创建文件夹监控对象,监视/system/framework目录

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

mFrameworkInstallObserver.startWatching();

//扫描/system/framework目录下的apk文件,扫描模式设置为非优化模式

scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR,scanMode | SCAN_NO_DEX, 0);

//在工厂模式下,调用函数scanDirLIOnly只扫描特定的apk文件

if(engModeEnable){

    //temp null

    mVendorAppDir = null;

    mDrmAppInstallObserver = null;

    mSystemAppDir = null;

    mAppInstallObserver = null;

    mSystemInstallObserver = null;

    mPreInstallObserver = null;

    mVendorInstallObserver = null;

    mAppInstallDir = null;

    Slog.i(TAG, " begin scan the apps !");

    scanDirLIOnly(PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

    Slog.i(TAG, " end scan the apps !");

    engModeEnable = false;

}else{//正常模式下

    //创建文件夹监控对象,监视/system/app目录

    mSystemAppDir = new File(Environment.getRootDirectory(), "app");

    mSystemInstallObserver = new AppDirObserver(

        mSystemAppDir.getPath(), OBSERVER_EVENTS, true);

    mSystemInstallObserver.startWatching();

    //扫描/system/app目录

    scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

    //创建文件夹监控对象,监视/vendor/app目录

    mVendorAppDir = new File("/vendor/app");

    mVendorInstallObserver = new AppDirObserver(

        mVendorAppDir.getPath(), OBSERVER_EVENTS, true);

    mVendorInstallObserver.startWatching();

    //扫描/vendor/app目录

    scanDirLI(mVendorAppDir, PackageParser.PARSE_IS_SYSTEM| PackageParser.PARSE_IS_SYSTEM_DIR, scanMode, 0);

 

    if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");

    mInstaller.moveFiles();

    // Prune any system packages that no longer exist.

    final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();

    if (!mOnlyCore) {

        //遍历Settings的成员变量mPackages

        Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();

        while (psit.hasNext()) {

            PackageSetting ps = psit.next();

            //不是系统app

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

                continue;

            }

            //如果是系统app,同时已经被PackageManagerService扫描过了

            final PackageParser.Package scannedPkg = mPackages.get(ps.name);

            if (scannedPkg != null) {

                //该apk包已不能使用

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

                    Slog.i(TAG, "Expecting better updatd system app for " + ps.name

                            + "; removing system app");

                    //移除该apk包信息

                    removePackageLI(scannedPkg, true);

                }

                continue;

            }

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

                psit.remove();

                String msg = "System package " + ps.name

                        + " no longer exists; wiping its data";

                reportSettingsProblem(Log.WARN, msg);

                mInstaller.remove(ps.name, 0);

                sUserManager.removePackageForAllUsers(ps.name);

            } else {

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

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

                    possiblyDeletedUpdatedSystemApps.add(ps.name);

                }

            }

        }

    }

    //mAppInstallDir = /data/app/

    mAppInstallDir = new File(dataDir, "app");

    //查找未完成安装的apk包

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

    //清除未完成安装包

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

        //clean up here

        cleanupInstallFailedPackage(deletePkgsList.get(i));

    }

    //删除临时文件

    deleteTempPackageFiles();
 

监控并扫描以下三个系统包安装目录:

/system/framework :该目录下的文件都是系统库

/system/app :该目录下是默认的系统应用

/vendor/app :该目录下是厂商定制的应用

最后扫描非系统apk信息


if (!mOnlyCore) {

    //标识数据扫描开始    EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,SystemClock.uptimeMillis());

    //创建文件夹监控对象,监视/data/app/目录

    mAppInstallObserver = new AppDirObserver(mAppInstallDir.getPath(), OBSERVER_EVENTS, false);

    mAppInstallObserver.startWatching();

    //扫描/data/app/目录下的apk文件

    scanDirLI(mAppInstallDir, 0, scanMode, 0);

    //创建文件夹监控对象,监视/system/preloadapp/目录

    mPreInstallObserver = new AppDirObserver(mPreInstallDir.getPath(), OBSERVER_EVENTS, false);

    mPreInstallObserver.startWatching();

    //扫描/system/preloadapp/目录下的apk文件

    scanDirLI(mPreInstallDir, 0, scanMode, 0);

    //创建文件夹监控对象,监视/data/app-private/目录

    mDrmAppInstallObserver = new AppDirObserver(mDrmAppPrivateInstallDir.getPath(), OBSERVER_EVENTS, false);

    mDrmAppInstallObserver.startWatching();

    //扫描/data/app-private/目录下的apk文件

    scanDirLI(mDrmAppPrivateInstallDir, PackageParser.PARSE_FORWARD_LOCK,scanMode, 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.

     */

    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; wiping its data";

            mInstaller.remove(deletedAppName, 0);

            sUserManager.removePackageForAllUsers(deletedAppName);

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

        }

        reportSettingsProblem(Log.WARN, msg);

    }

} else {

    mPreInstallObserver = null;

    mAppInstallObserver = null;

    mDrmAppInstallObserver = null;

}
 

监控并扫描以下三个数据目录:

/data/app/

/system/preloadapp/

/data/app-private/

最后进入结尾阶段,将扫描到的信息保存到文件中。


mFlagInstall = true;

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,SystemClock.uptimeMillis());

final boolean regrantPermissions = mSettings.mInternalSdkPlatform != mSdkVersion;

mSettings.mInternalSdkPlatform = mSdkVersion;

updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL | (regrantPermissions

                ? (UPDATE_PERMISSIONS_REPLACE_PKG|UPDATE_PERMISSIONS_REPLACE_ALL): 0));

ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();

for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) {

    if (mActivities.mActivities.get(pa.mPref.mComponent) == null) {

        removed.add(pa);

    }

}

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

    PreferredActivity pa = removed.get(i);

    Slog.w(TAG, "Removing dangling preferred activity: "

            + pa.mPref.mComponent);

    mSettings.mPreferredActivities.removeFilter(pa);

}

// can downgrade to reader

mSettings.writeLPr();

 

EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,SystemClock.uptimeMillis());

Runtime.getRuntime().gc();

mRequiredVerifierPackage = getRequiredVerifierLPr();
 

至此,PackageManagerService就构造完成了,构造过程认为繁重,Apk文件扫描解析耗费比较长的时间,这是导致开机速度慢的原因。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值