PackageManagerService 系列文章以下(基于 Android 9.0 源码)
🍁 Framework 核心服务之 PackageManagerService 钻研(1)- 启动流程
🍁 Framework 核心服务之 PackageManagerService 钻研(2)- 构造函数
🍁 Framework 核心服务之 PackageManagerService 钻研(3)- PackageManager
🍁 Framework 核心服务之 PackageManagerService 钻研(4)- PackageInstaller
🍁 Framework 核心服务之 PackageManagerService 钻研(5)- APK 安装流程(PackageInstaller)
🍁 Framework 核心服务之 PackageManagerService 钻研(6)- APK 安装流程(PMS)
🍁 Framework 核心服务之 PackageManagerService 钻研(7)- PackageParserjava
关键类 | 路径 |
---|---|
Context.java | frameworks/base/core/java/android/content/Context.java |
ContextImpl.java | frameworks/base/core/java/android/app/ContextImpl.java |
PackageManager.java | frameworks/base/core/java/android/content/pm/PackageManager.java |
ApplicationPackageManager.java | frameworks/base/core/java/android/app/ApplicationPackageManager.java |
ActivityThread.java | frameworks/base/core/java/android/app/ActivityThread.java |
PackageManager 是一个抽象类:android
/** * Class for retrieving various kinds of information related to the application * packages that are currently installed on the device. * * You can find this class through {@link Context#getPackageManager}. */ public abstract class PackageManager {
注释能够看出:PackageManager 这个类是检测当前已经安装在当前设备上的应用程序包的信息。你能够调用 Context 类的 getPackageManager() 方法来获取 PackageManager。segmentfault
PackageManager 是一个实际上管理应用程序安装、卸载和升级的 API。当咱们安装 APK 文件时,PackageManager 会解析 APK 包文件和显示确认信息。当咱们点击 OK 按钮后,PackageManager 会调用一个叫 "InstallPackage" 的方法,这个方法有 4 个参数,也就是 uri、installFlags、observer、installPackagename。PackageManager 会启动一个叫 "package" 的 servcie 服务,如今全部模糊的东西会发生在这个 service 中。缓存
✨ 一、安装、卸载应用
✨ 二、查询 permission 相关信息
✨ 三、查询 Application 相关信息(application、activity、receiver、service、provider 及相应属性等)
✨ 四、查询已安装应用
✨ 五、增长、删除 permission
✨ 六、清除用户数据、缓存、代码等安全
/** * Retrieve overall information about an application package that is * installed on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the * desired package. * @param flags Additional option flags to modify the data returned. * @return A PackageInfo object containing information about the package. If * flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the package * is not found in the list of installed applications, the package * information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 经过包名获取该包名对应的应用程序的 PackageInfo 对象, * PackageInfo 类包含了从 AndroidManifest.xml 文件中收集的全部信息。 */ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular * package/application. * * @param packageName The full name (i.e. com.google.apps.contacts) of an * application. * @param flags Additional option flags to modify the data returned. * @return An {@link ApplicationInfo} containing information about the * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if * the package is not found in the list of installed applications, * the application information is retrieved from the list of * uninstalled applications (which includes installed applications * as well as applications with data directory i.e. applications * which had been deleted with {@code DONT_DELETE_DATA} flag set). * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 根据包名返回其对应的 ApplicationInfo 信息。 */ public abstract ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular activity * class. * * @param component The full component name (i.e. * com.google.apps.contacts/com.google.apps.contacts. * ContactsList) of an Activity class. * @param flags Additional option flags to modify the data returned. * @return An {@link ActivityInfo} containing information about the * activity. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 检索出一个特定的 Activity 类的全部信息。 */ public abstract ActivityInfo getActivityInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular receiver * class. * * @param component The full component name (i.e. * com.google.apps.calendar/com.google.apps.calendar. * CalendarAlarm) of a Receiver class. * @param flags Additional option flags to modify the data returned. * @return An {@link ActivityInfo} containing information about the * receiver. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 检索出一个特定的 Receiver 类的全部信息(这里主要指 ActivityInfo)。 */ public abstract ActivityInfo getReceiverInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular service class. * * @param component The full component name (i.e. * com.google.apps.media/com.google.apps.media. * BackgroundPlayback) of a Service class. * @param flags Additional option flags to modify the data returned. * @return A {@link ServiceInfo} object containing information about the * service. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 检索出一个特定的 Service 类的全部信息(这里主要指 ServiceInfo)。 */ public abstract ServiceInfo getServiceInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the information we know about a particular content * provider class. * * @param component The full component name (i.e. * com.google.providers.media/com.google.providers.media. * MediaProvider) of a ContentProvider class. * @param flags Additional option flags to modify the data returned. * @return A {@link ProviderInfo} object containing information about the * provider. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 检索出一个特定的 content provider 类的全部信息(这里主要指 ProviderInfo)。 */ public abstract ProviderInfo getProviderInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException;
/** * Return a List of all packages that are installed for the current user. * * @param flags Additional option flags to modify the data returned. * @return A List of PackageInfo objects, one for each installed package, * containing information about the package. In the unlikely case * there are no installed packages, an empty list is returned. If * flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package * information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). * * 获取设备上安装的全部软件包。 */ public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
/** * Map from the current package names in use on the device to whatever * the current canonical name of that package is. * @param names Array of current names to be mapped. * @return Returns an array of the same size as the original, containing * the canonical name for each package. * * 从设备上使用当前包名映射到该软件包名的当前规范名称, * 若是修改包名会用到,没有修改过包名通常不会用到。 */ public abstract String[] currentToCanonicalPackageNames(String[] names);
/** * Map from a packages canonical name to the current name in use on the device. * @param names Array of new names to be mapped. * @return Returns an array of the same size as the original, containing * the current name for each package. * * 将软件包规范名称映射到设备上正在使用的当前名称, * 咱们发现:canonicalToCurrentPackageNames() 和 currentToCanonicalPackageNames() 方法是相反的两个方法 */ public abstract String[] canonicalToCurrentPackageNames(String[] names);
/** * Retrieve all of the information we know about a particular permission. * * @param name The fully qualified name (i.e. com.google.permission.LOGIN) * of the permission you are interested in. * @param flags Additional option flags to modify the data returned. * @return Returns a {@link PermissionInfo} containing information about the * permission. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 检测出咱们想要知道的全部关于权限的信息。 */ public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags) throws NameNotFoundException;
/** * Query for all of the permissions associated with a particular group. * * @param group The fully qualified name (i.e. com.google.permission.LOGIN) * of the permission group you are interested in. Use null to * find all of the permissions not associated with a group. * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionInfo} containing information * about all of the permissions in the given group. * @throws NameNotFoundException if a package with the given name cannot be * found on the system. * * 查询与特定组相关的全部权限。 */ public abstract List<PermissionInfo> queryPermissionsByGroup(String group, @PermissionInfoFlags int flags) throws NameNotFoundException;
/** * Retrieve all of the known permission groups in the system. * * @param flags Additional option flags to modify the data returned. * @return Returns a list of {@link PermissionGroupInfo} containing * information about all of the known permission groups. * * 检索出系统中全部已知的权限。 */ public abstract List<PermissionGroupInfo> getAllPermissionGroups( @PermissionGroupInfoFlags int flags);
固然除了上面列举出来的方法之外,还有其余不少方法,咱们再也不一一列出来,若是后面分析遇到会再单独拿出来分析!app
接下来咱们来看看 PackageManager 中关于安装的几个方法!ide
/** * packageURI:表示安装的路径,能够是 "file:" 或者 "content:" 的 URI * observer: 一个回调的观察者,有了这个观察者,就能够在软件包安装完成后获得安装结果的通知。 * 若是安装完成会调用这个观察者 IPackageInstallObserver 的 packageInstalled(String,int)方法,observer这个入参不能为空。 * flags: 标志位参数 * nstallerPackageName:正在进行安装的安装包包名 */ /** * @deprecated replaced by {@link PackageInstaller} * @hide */ @Deprecated public abstract void installPackage( // 弃用 Uri packageURI, IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName); /** * @deprecated replaced by {@link PackageInstaller} * @hide */ @Deprecated public abstract void installPackage( // 弃用 Uri packageURI, PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName);
从 8.1 开始,已经弃用了 installPackage 方法(9.0 的代码中已经去除 installPackage 代码了),而是使用 PackageInstaller 执行应用的安装、升级和删除操做。函数
/** * Return interface that offers the ability to install, upgrade, and remove * applications on the device. */ public abstract @NonNull PackageInstaller getPackageInstaller();
/** * If there is already an application with the given package name installed * on the system for other users, also install it for the calling user. * @hide */ @SystemApi // 系统 API public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
经过注释能够看出这个方法的用途:若是系统上已经安装相同包名的应用程序,则重复从新安装。this
咱们知道 PackageManager 是一个抽象类,它里面很重要的方法都是抽象的,因此在具体执行的时候,确定是它的实现子类,那么咱们就来看下它的具体实现类。google
前面咱们讲解 PackageManager 类的时候,官网推荐获取 PackageManager 对象的方法是 Context 的 Context#getPackageManager() 方法,那咱们来看下:
// frameworks/base/core/java/android/content/Context.java /** Return PackageManager instance to find global package information. */ public abstract PackageManager getPackageManager();
咱们知道 Context 也是一个抽象类,而它的 getPackageManager() 也是抽象方法,但 Context 的具体实现类是 ContextImpl,那咱们就去 ContextImpl 里面看下:
/** * Common implementation of Context API, which provides the base * context object for Activity and other application components. * @hide */ public class ContextImpl extends Context { private PackageManager mPackageManager; ... ... @Override public PackageManager getPackageManager() { // 判断 mPackageManager 是否为空,若是为空,则说明是第一次调用 if (mPackageManager != null) { return mPackageManager; } // 调用 ActivityThread 的静态方法 getPackageManager() 获取一个 IPackageManager 对象 IPackageManager pm = ActivityThread.getPackageManager(); // 若是获取的 IPackageManager 对象不为空,则构造一个 ApplicationPackageManager 对象,ApplicationPackageManager 是 PackageManager 的子类 if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); } return null; } ... ... }
因此,在咱们平时调用 Context 的 getPackageManager()方法后,其实返回的是 ApplicationPackageManager 这个类。
咱们先来看下 ApplicationPackageManager 类的源码:
/** @hide */ public class ApplicationPackageManager extends PackageManager {
经过源码咱们知道 ApplicationPackageManager 继承自PackageManager,并且 ApplicationPackageManager 类不是抽象的,因此 ApplicationPackageManager 必然实现了 PackageManager 的全部抽象方法。
protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) { mContext = context; mPM = pm; }
在讲解 PackageManager 的时候,咱们提到过安装 APK 会调用 InstallPackage 方法(Android 8.1,9.0 已弃用),咱们看下在 ApplicationPackageManager 中的具体实现:
@Override public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName) { installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags, installerPackageName, mContext.getUserId()); }
// 源码来自:Android 8.1,9.0 已弃用 private void installCommon(Uri packageURI, PackageInstallObserver observer, int flags, String installerPackageName, int userId) { // scheme 判断,若是非 "file" 则抛异常,由于只支持 file 格式的 URI if (!"file".equals(packageURI.getScheme())) { throw new UnsupportedOperationException("Only file:// URIs are supported"); } // 获取相应的路径 final String originPath = packageURI.getPath(); try { // 调用 installPackageAsUser 方法 mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName, userId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
能够发现,public abstract void installPackage() 方法其内部本质是调用的 IPackageManager 的 installPackageAsUser() 方法。
咱们先来看看以下代码(上面没有分析):
// 调用 ActivityThread 的静态方法 getPackageManager() 获取一个 IPackageManager 对象 IPackageManager pm = ActivityThread.getPackageManager();
跟踪 getPackageManager():
static volatile IPackageManager sPackageManager; public static IPackageManager getPackageManager() { // 判断 sPackageManager 是否为空,若是为空,则说明是的第一次调用,走第二步,若是不为空,则直接返回 sPackageManager if (sPackageManager != null) { return sPackageManager; } // 能走到第二步,说明这是第一次调用,则调用 ServiceManager 的 getService(String) 方法获取一个 IBinder 对象 IBinder b = ServiceManager.getService("package"); // 调用 IPackageManager.Stub.asInterface(IBinder) 获取一个 sPackageManager 对象 sPackageManager = IPackageManager.Stub.asInterface(b); return sPackageManager; }
在上面分析 ContextImpl 的 getPackageManager() 方法里面,咱们知道:
IPackageManager pm = ActivityThread.getPackageManager(); if (pm != null) { // Doesn't matter if we make more than one instance. return (mPackageManager = new ApplicationPackageManager(this, pm)); }
而在 ActivityThread 的静态方法 getPackageManager() 里面:
sPackageManager = IPackageManager.Stub.asInterface(b); return sPackageManager;
因此在 ApplicationPackageManager 里面的 mPM 其实就是 IPackageManager.Stub 内部类 Proxy 对象。
那对应的 IPackageManager.Stub 是什么?其实就是 PackageManagerService.java 。
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {
以下图所示:
结合上面的知识,再结合 PackageManager、ApplicationPackageManager 和 PackageManagerService 总结以下:
✨ IPackageManager 负责通讯:IPackageManager 接口类中定义了不少业务方法,可是因为安全等方面的考虑,Android 对外(即SDK)提供的仅仅是一个子集,该子集被封装在抽象类 PackageManager 中。客户端通常经过 Context 的 getPackageManager 函数返回一个类型为 PackageManager 的对象,该对象的实际类型是 PackageManager 的子类 ApplicationPackageManager 。ApplicationPackageManager 并无直接参与 Binder 通讯,而是经过 mPM 成员变量指向了一个 IPackageManager.Stub.Proxy 类型的对象。
✨ AIDL中 的 Binder 服务端是 PackageManagerService,由于 PackageManagerService 继承自 IPackageManager.Stub 。因为 IPackageManager.Stub 类从 Binder 派生,因此 PackageManagerService 将做为服务端参与 Binder 通讯。
✨ AIDL中 的 Binder 客户端是 ApplicationPackageManager 中成员变量 mPM,由于mPM内部指向的是 IPackageManager.Stub.Proxy。
总体流程的 Binder 结构大体以下:
01. https://www.jianshu.com/p/c56...
02. https://www.jianshu.com/p/a30...