zoukankan      html  css  js  c++  java
  • 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介于10001999之间,而对于系统应用,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介于10001999之间的SharedUserSetting对象添加到mUserIds数组中,通过UID来索引数组元素。


    UID小于1000SharedUserSetting保存到数组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");

    首先创建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;
    }

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

    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
    ");
    			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
    ");
    				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文件扫描解析耗费比较长的时间,这是导致开机速度慢的原因。



















  • 相关阅读:
    新建MDK工程
    winform如何打开电脑自带小软件
    Winform界面适应不同分辨率
    c#如何为pictureBox控件写单击事件
    winform如何获取记事本内容显示在listBox控件中
    winform如何单击X按钮弹出对话框
    win10系统如何使用自带的备份功能
    模拟iis账号权限
    (转发)在ASP.NET MVC中以post方式传递数组参数的示例
    .net开发windows服务小结 (转发)
  • 原文地址:https://www.cnblogs.com/keanuyaoo/p/3306406.html
Copyright © 2011-2022 走看看