Android Framework--PackageManagerService
来源:互联网 发布:java api pdf 编辑:程序博客网 时间:2024/06/05 14:09
PackageManagerService负责Package的管理、应用程序的安装、卸载以及提供应用程序的信息查询
PKMS的启动过程
通过 Android Framework–启动流程 一文我们知道SystemServer阶段会启动各种服务,其中就包括PKMS
在SystemServer.java的run中
private void run() { ... // Start services. try { startBootstrapServices(); startCoreServices(); startOtherServices(); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } ...}
PKMS的启动代码就在startBootstrapServices中
private void startBootstrapServices() { ...// Start the package manager.Slog.i(TAG, "Package Manager");//①调用main启动mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);mFirstBoot = mPackageManagerService.isFirstBoot();mPackageManager = mSystemContext.getPackageManager(); ...}
startOtherServices()中也有PKMS的相关设置
private void startOtherServices(){ ...try {//做dex优化 mPackageManagerService.performBootDexOpt();} catch (Throwable e) { reportWtf("performing boot dexopt", e);} ...try {//通知系统PKMS已经就绪 mPackageManagerService.systemReady();} catch (Throwable e) { reportWtf("making Package Manager Service ready", e);} ...}
看①
public static final IPackageManager main(Context context,boolean factoryTest,boolean onlyCore){ PackageManagerService m = new PackageManagerService(context,factoryTest,onlyCore); ServiceManager.addService("package",m); return m;}
这边会构造一个PackageManagerService并把自己加载ServiceManager中。构造函数主要做了三阶段:扫描目标文件夹之前的准备工作、扫描目标文件夹、扫描后的工作。这部分非常耗时,也是Android启动很久的原因之一
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { ... //①-1 扫描前准备工作 //保存屏幕相关信息 this.mMetrics = new DisplayMetrics(); //保存系统运行过程中的一些设置 this.mSettings = new Settings(context); //①-1.1为进程添加权限 (字符串,用户id,标志系统package) this.mSettings.addSharedUserLPw("android.uid.system", 1000, 1073741825); this.mSettings.addSharedUserLPw("android.uid.phone", 1001, 1073741825); this.mSettings.addSharedUserLPw("android.uid.log", 1007, 1073741825); this.mSettings.addSharedUserLPw("android.uid.nfc", 1027, 1073741825); this.mSettings.addSharedUserLPw("android.uid.bluetooth", 1002, 1073741825); this.mSettings.addSharedUserLPw("android.uid.shell", 2000, 1073741825); ... //HandlerThread是一个带消息循环的线程,这个线程主要处理安装和卸载APK的任务 this.mHandlerThread = new ServiceThread("PackageManager", 10, true); this.mHandlerThread.start(); this.mHandler = new PackageManagerService.PackageHandler(this.mHandlerThread.getLooper()); Watchdog.getInstance().addThread(this.mHandler, 600000L); //获取/data/目录下各目录对象 File dataDir = Environment.getDataDirectory(); this.mAppDataDir = new File(dataDir, "data"); //指向 /data/app/ 下面的雷同 this.mAppInstallDir = new File(dataDir, "app"); this.mAppLib32InstallDir = new File(dataDir, "app-lib"); this.mAsecInternalPath = (new File(dataDir, "app-asec")).getPath(); this.mUserAppDataDir = new File(dataDir, "user"); this.mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); //UserManager 目前没用,预测支持Android多用户 sUserManager = new UserManagerService(context, this, this.mInstallLock, this.mPackages); //①-1.2 读取并解析 /etc/permission/ 下的xml文件并保存起来,这些文件描述了设备支持的硬件特性 readPermissions(); //①-1.3 读取三个文件的数据状态(上次保存的取出来与最新的进行对比即可知道apk是否更新了等信息) this.mRestoredSettings = this.mSettings.readLPw();}
①-1中有权限相关的知识
linux系统中每个进程都有一个UID(用户id)并且可以有多个GID(组id),linux的权限是根据组来的。比如进程1000需要读写SD卡权限,则需要把进程1000加到读写SD卡权限组(GID=1015)中即可
这部分定义在Process.java中
①-1.2中有关设备硬件特性的知识
简单来讲这部分有多个xml文件组成,每个文件描述一部分类型,例如设备对蓝牙的支持、对前置摄像头的支持、对gps、wifi、gsm等等的支持
①-1.3中读取的三个文件
- packages.xml 扫描完目标文件夹后会创建该文件,当系统进行程序安装、卸载荷更新等操作均会更新该文件
- packages.list 描述系统中存在的所有非系统自带的APK信息。当这些程序有变动时,PKMS就会更新该文件
- packages-stopped.xml 从系统自带的设置程序中进入应用程序页面,然后在选择强制停止某个应用时,系统会将该应用的相关信息记录到此文件中。
//接上面的构造函数 ... //①-2扫描任务 //①-2.1 对多个目录的APK进行扫描 File frameworkDir = new File(Environment.getRootDirectory(), "framework"); this.scanDirLI(frameworkDir, 193, 418, 0L); File vendorOverlayDir = new File("/vendor/overlay"); this.scanDirLI(vendorOverlayDir, 65, 928, 0L); File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app"); this.scanDirLI(privilegedAppDir, 193, 416, 0L); File systemAppDir = new File(Environment.getRootDirectory(), "app"); this.scanDirLI(systemAppDir, 65, 416, 0L); File vendorAppDir = new File("/vendor/app"); this.scanDirLI(vendorAppDir, 65, 416, 0L); File oemAppDir = new File(Environment.getOemDirectory(), "app"); //①-2.2 扫描apk this.scanDirLI(oemAppDir, 65, 416, 0L);
①-2.1 这边可以看到用scanDirLi对多个目录进行扫描,这些目录分别是
- /system/frameworks 该目录下的文件都是系统库,framework.jar、services.jar、framework-res.apk;不过scanDirLi只扫描apk,所以这里只会扫描framework-res.apk
- /vendor/overlay 厂商用来替换系统默认应用(比如时钟等,但很多厂商没有放这里)
- /system/priv-app 4.4之后增加,放系统核心应用(Launcher,systemui, settingsprovider),拥有系统级权限
- /system/app 该目录下的都是系统默认应用,Browser.apk等
- /vendor/app 该目录下的都是厂商定制的应用
- /oem/app
①-2.2中对apk进行了扫描,其主要做了以下几件事
- 利用PackageParser解析AndroidManifest.xml文件获取包信息保存在Package对象中
- 根据AndroidManifest.xml提供的信息处理APK的permission、service、activity、provider等
//接上面的构造函数 ... //①-3 扫尾工作,将上面拿到的信息整合下保存下来 //汇总并更新和Permission相关的信息 this.updatePermissionsLPw((String)null, (Package)null, 1 | (regrantPermissions?6:0)); //将信息写到package.xml package.list 及 package-stopped.xml中 this.mSettings.writeLPr(); this.mRequiredVerifierPackage = this.getRequiredVerifierLPr();
APK Install
APK的安装会调用PKMS的installPackageAsUser
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer, int installFlags, String installerPackageName, VerificationParams verificationParams, String packageAbiOverride, int userId) { //检查客户端是否有安装package的权限 this.mContext.enforceCallingOrSelfPermission("android.permission.INSTALL_PACKAGES", (String)null); int callingUid = Binder.getCallingUid(); this.enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser"); if(this.isUserRestricted(userId, "no_install_apps")) { try { if(observer != null) { observer.onPackageInstalled("", -111, (String)null, (Bundle)null); } } catch (RemoteException var13) { ; } } else { if(callingUid != 2000 && callingUid != 0) { installFlags &= -33; installFlags &= -65; } else { installFlags |= 32; } UserHandle user; if((installFlags & 64) != 0) { user = UserHandle.ALL; } else { user = new UserHandle(userId); } verificationParams.setInstallerUid(callingUid); File originFile = new File(originPath); PackageManagerService.OriginInfo origin = PackageManagerService.OriginInfo.fromUntrustedFile(originFile); //INIT_COPY = 5 Message msg = this.mHandler.obtainMessage(5); msg.obj = new PackageManagerService.InstallParams(origin, observer, installFlags, installerPackageName, verificationParams, user, packageAbiOverride); //发送Handler消息 this.mHandler.sendMessage(msg); } }
接收方在PackageHandler中,看下INIT_COPY分支
case INIT_COPY: { HandlerParams params = (HandlerParams) msg.obj; //idx为当前等待处理的安装请求个数 int idx = mPendingInstalls.size(); if (DEBUG_INSTALL) Slog.i(TAG, "init_copy idx=" + idx + ": " + params); // If a bind was already initiated we dont really // need to do anything. The pending install // will be processed later on. if (!mBound) { // If this is the only one pending we might // have to bind to the service again. //安装的时候需要DefaultContainerService提供服务,该服务由DefaultCotainerService.apk提供 if (!connectToService()) { Slog.e(TAG, "Failed to bind to media container service"); params.serviceError(); return; } else { // Once we bind to the service, the first // pending request will be processed. mPendingInstalls.add(idx, params); } } else { mPendingInstalls.add(idx, params); // Already bound to the service. Just make // sure we trigger off processing the first request. if (idx == 0) { //跑下一个分支 MCS_BOUND mHandler.sendEmptyMessage(MCS_BOUND); } } break;}
MCS_BOUND分支
case MCS_BOUND: { if (msg.obj != null) { mContainerService = (IMediaContainerService) msg.obj; } if (mContainerService == null) { //如果ContainerService为空则进行不了,直接清空安装请求了 for (HandlerParams params : mPendingInstalls){ params.serviceError(); } mPendingInstalls.clear(); } else if (mPendingInstalls.size() > 0) { HandlerParams params = mPendingInstalls.get(0); if (params != null) { //执行startCopy,然后移除一个安装请求,如果还有请求则继续跑该分支,没有的话则发送MSC_UNBIND发送断交请求与ContainerService断开联系 if (params.startCopy()) { if (mPendingInstalls.size() > 0){ mPendingInstalls.remove(0); } if (mPendingInstalls.size() == 0) { if (mBound) { removeMessages(MCS_UNBIND); Message ubmsg = obtainMessage(MCS_UNBIND); sendMessageDelayed(ubmsg, 10000); } } else { mHandler.sendEmptyMessage(MCS_BOUND); } } } } else { // Should never happen ideally. Slog.w(TAG, "Empty queue"); } break;}
看下PackageManagerService.HandlerParams.startCopy
final boolean startCopy() { boolean res; try { //MAX_RETRIES初始为4,即安装会尝试4次 if (++mRetries > MAX_RETRIES) { mHandler.sendEmptyMessage(MCS_GIVE_UP); handleServiceError(); return false; } else { //调用派生类的handleStartCopy安装 handleStartCopy(); res = true; } } catch (RemoteException e) { mHandler.sendEmptyMessage(MCS_RECONNECT); res = false; } //返回处理结果 handleReturnCode(); return res;}
handleStartCopy会对安装路径等信息做检查并将APK从临时文件夹/data/local/tmp/目录移到/data/app目录下,完成安装,最终调用POST_INSTALL分支。POST_INSTALL会进行扫尾处理,通知pm。
queryIntentActivities
PKMS提供Activity、Service、BroadcastReceiver等通过IntentFilter的查询功能
public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { if (!sUserManager.exists(userId)) return Collections.emptyList(); enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities"); ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { intent = intent.getSelector(); comp = intent.getComponent(); } } //第一种:根据ComponentName获取ActivityInfo返回查询结果 if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { final ResolveInfo ri = new ResolveInfo(); //ResolveInfo的activityInfo指向查询到的ActivityInfo ri.activityInfo = ai; list.add(ri); } return list; } // synchronized (mPackages) { final String pkgName = intent.getPackage(); //第二种情况,如果package也没有信息,则进行全系统范围内匹配 if (pkgName == null) { List<CrossProfileIntentFilter> matchingFilters = getMatchingCrossProfileIntentFilters(intent, resolvedType, userId); // Check for results that need to skip the current profile. ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent, resolvedType, flags, userId); if (resolveInfo != null) { List<ResolveInfo> result = new ArrayList<ResolveInfo>(1); result.add(resolveInfo); return result; } // Check for cross profile results. resolveInfo = queryCrossProfileIntents( matchingFilters, intent, resolvedType, flags, userId); // Check for results in the current profile. //进行全系统范围内匹配 List<ResolveInfo> result = mActivities.queryIntent( intent, resolvedType, flags, userId); if (resolveInfo != null) { result.add(resolveInfo); Collections.sort(result, mResolvePrioritySorter); } return result; } //第三种:有package信息,根据package进行查询 final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mActivities.queryIntentForPackage(intent, resolvedType, flags, pkg.activities, userId); } return new ArrayList<ResolveInfo>(); } }
- Android Framework--PackageManagerService
- Android Framework 之PackageManagerService详细分析
- Android framework 应用安装流程 分析 PackageManagerService(Android5.1)
- 【Android】PackageManagerService
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析 .
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService详细分析
- Android PackageManagerService启动过程
- Android PackageManagerService详细分析
- android的PackageManagerService详解
- Android M PackageManagerService解析
- python之获取本地文件名称
- 2.3 寻找发帖“水王”
- jquery中使用eval()函数
- 分析redis的RDB和AOF两种持久化机制的工作原理
- VB 学习整理3 输入和输出
- Android Framework--PackageManagerService
- [协同过滤]:交替最小二乘法
- Vue v-if条件渲染
- 鼠标滑过旋转360
- 怎样才能赚到钱系列(五)
- Eclipse异常终止或电脑断电等异常死机问题导致文件lock无法提交的问题
- 抽奖系统Demo
- C语言整型指针理解
- 回溯法简单应用--解数独