PKMS 钻研(3) - PackageManager

核心源码(Android_10.0)

关键类 路径
Context.java frameworks/base/core/java/android/content/Context.java
ContextImpl.java frameworks/base/core/java/android/app/ContextImpl.java
ActivityThread.java frameworks/base/core/java/android/app/ActivityThread.java
PackageManager.java frameworks/base/core/java/android/content/pm/PackageManager.java
ApplicationPackageManager.java frameworks/base/core/java/android/app/ApplicationPackageManager.java

一、PackageManager

1.1 简介

PackageManager 是一个抽象类:

1
2
3
4
5
6
7
8
9
// frameworks/base/core/java/android/content/pm/PackageManager.java

/**
* 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

1.2 安装原理

PackageManager 是一个实际上管理应用程序 安装卸载升级API

当我们安装 APK 文件时,PackageManager 会解析 APK 包文件和显示确认信息。

当我们点击 OK 按钮后,PackageManager 会调用一个叫 InstallPackage 的方法,这个方法有 4 个参数,也就是 uriinstallFlagsobserverinstallPackagename

PackageManager 会启动一个叫 "package" 的 servcie 服务,现在所有模糊的东西会发生在这个 service 中。

1.3 实现功能

抽象类 PackageManager 提供的功能,主要有以下几点:

        ✒ 1、 安装、卸载应用
        ✒ 2、 查询 permission 相关信息
        ✒ 3、 查询 Application 相关信息(application、activity、receiver、service、provider 及相应属性等)
        ✒ 4、 查询已安装应用
        ✒ 5、 增加、删除 permission
        ✒ 6、 清除用户数据、缓存、代码等

1.4 抽象方法

我们来看几个比较重要的抽象方法:

getPackageInfo()

1
2
3
4
5
6
7
/**
* 通过包名获取该包名对应的应用程序的 PackageInfo 对象,
* PackageInfo 类包含了从 AndroidManifest.xml 文件中收集的所有信息。
*/
public abstract PackageInfo getPackageInfo(@NonNull String packageName,
@PackageInfoFlags int flags)
throws NameNotFoundException;

getApplicationInfo()

1
2
3
4
5
6
/**
* 根据包名返回其对应的 ApplicationInfo 信息。
*/
@NonNull
public abstract ApplicationInfo getApplicationInfo(@NonNull String packageName,
@ApplicationInfoFlags int flags) throws NameNotFoundException;

getActivityInfo()

1
2
3
4
5
6
/**
* 检索出一个特定的 Activity 类的所有信息。
*/
@NonNull
public abstract ActivityInfo getActivityInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;

getReceiverInfo()

1
2
3
4
5
6
/**
* 检索出一个特定的 Receiver 类的所有信息(这里主要指 ActivityInfo)。
*/
@NonNull
public abstract ActivityInfo getReceiverInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;

getServiceInfo()

1
2
3
4
5
6
/**
* 检索出一个特定的 Service 类的所有信息(这里主要指 ServiceInfo)。
*/
@NonNull
public abstract ServiceInfo getServiceInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;

getProviderInfo()

1
2
3
4
5
6
/**
* 检索出一个特定的 content provider 类的所有信息(这里主要指 ProviderInfo)。
*/
@NonNull
public abstract ProviderInfo getProviderInfo(@NonNull ComponentName component,
@ComponentInfoFlags int flags) throws NameNotFoundException;

getInstalledPackages()

1
2
3
4
5
/**
* 获取设备上安装的所有软件包。
*/
@NonNull
public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);

currentToCanonicalPackageNames()

1
2
3
4
5
/**
* 从设备上使用当前包名映射到该软件包名的当前规范名称,
* 如果修改包名会用到,没有修改过包名一般不会用到。
*/
public abstract String[] currentToCanonicalPackageNames(@NonNull String[] packageNames);

canonicalToCurrentPackageNames()

1
2
3
4
5
/**
* 将软件包规范名称映射到设备上正在使用的当前名称,
* canonicalToCurrentPackageNames() 和 currentToCanonicalPackageNames() 方法是相反的两个方法
*/
public abstract String[] canonicalToCurrentPackageNames(@NonNull String[] packageNames);

getPermissionInfo()

1
2
3
4
5
/**
* 检测出我们想要知道的所有关于权限的信息。
*/
public abstract PermissionInfo getPermissionInfo(@NonNull String permissionName,
@PermissionInfoFlags int flags) throws NameNotFoundException;

queryPermissionsByGroup()

1
2
3
4
5
6
/**
* 查询与特定组相关的所有权限。
*/
@NonNull
public abstract List<PermissionInfo> queryPermissionsByGroup(@NonNull String permissionGroup,
@PermissionInfoFlags int flags) throws NameNotFoundException;

getAllPermissionGroups()

1
2
3
4
5
6
/**
* 检索出系统中所有已知的权限。
*/
@NonNull
public abstract List<PermissionGroupInfo> getAllPermissionGroups(
@PermissionGroupInfoFlags int flags);

除了上面列举出来的方法以外,还有很多其他抽象方法,这边不再一一列举出来,如果后面分析遇到会再单独拿出来分析!

1.5 安装方法

接下来我们来看看 PackageManager 中关于安装的几个方法!

InstallPackage(弃用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* 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() 方法(源码中已经去除),而是使用 PackageInstaller 执行应用的安装、升级和删除操作

getPackageInstaller

1
2
3
4
5
/**
* Return interface that offers the ability to install, upgrade, and remove
* applications on the device.
*/
public abstract @NonNull PackageInstaller getPackageInstaller();

installExistingPackage

1
2
3
4
5
6
7
/**
* 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;

通过注释可以看出这个方法的用途:如果系统上已经安装相同包名的应用程序,则重新安装。

1.6 具体实现类

我们知道 PackageManager 是一个抽象类,定义了很多抽象方法,所以在具体执行的时候,肯定是由它的子类去实现,它的子类是什么?

前面我们讲解 PackageManager 类的时候,官方推荐通过 Context#getPackageManager() 方法获取 PackageManager 对象:

1.6.1 Context.getPackageManager

1
2
3
4
5
6
7
8
9
10
// frameworks/base/core/java/android/content/Context.java

public abstract class Context {
... ...

/** Return PackageManager instance to find global package information. */
public abstract PackageManager getPackageManager();

... ...
}

Context 也是一个抽象类,而它的 getPackageManager() 也是抽象方法,Context 的具体实现类是 ContextImpl,那我们就去 ContextImpl 里面看下:

1.6.2 ContextImpl.getPackageManager

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// frameworks/base/core/java/android/app/ContextImpl.java

/**
* Common implementation of Context API, which provides the base
* context object for Activity and other application components.
*/
class ContextImpl extends Context {
... ...

@UnsupportedAppUsage
private PackageManager mPackageManager;
... ...

@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) { // 判断 mPackageManager 是否为空,如果为空,则说明是第一次调用
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

我们先来看下 ApplicationPackageManager 的源码:

1
2
3
4
// frameworks/base/core/java/android/app/ApplicationPackageManager.java

/** @hide */
public class ApplicationPackageManager extends PackageManager {

ApplicationPackageManager 继承自 PackageManager,而且 ApplicationPackageManager 类不是抽象的,所以 ApplicationPackageManager 必然实现了 PackageManager所有抽象方法

2.1 构造函数

1
2
3
4
5
6
7
8
9
10
11
12
public class ApplicationPackageManager extends PackageManager {
... ...

private final ContextImpl mContext;
private final IPackageManager mPM;

protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
mContext = context;
mPM = pm;
}
... ...
}

2.2 InstallPackage(弃用)

在讲解 PackageManager 的时候,我们提到过安装 APK 会调用 InstallPackage 方法(Android 8.1,9.0 已弃用)。

1
2
3
4
5
6
@Override
public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
String installerPackageName) {
installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
installerPackageName, mContext.getUserId());
}

2.3 installCommon(弃用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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();
}
}

可以发现,installPackage() 方法其内部本质是调用的 IPackageManagerinstallPackageAsUser() 方法,因为方法已经弃用,我们这边不再跟下去。

2.4 getPackageInstaller

之前我们说过,从 8.1 开始调用 getPackageInstaller 方法,那么我们来看看源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class ApplicationPackageManager extends PackageManager {
... ...

@Override
public PackageInstaller getPackageInstaller() {
synchronized (mLock) {
if (mInstaller == null) {
try {
mInstaller = new PackageInstaller(mPM.getPackageInstaller(),
mContext.getPackageName(), mContext.getUserId());
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
return mInstaller;
}
}
... ...
}

到这边,一切都明朗了,PackageManager 中创建了 PackageInstaller 对象,关于 PackageInstaller 的具体内容,我们这边不再继续分析。

具体内容,请查阅博文:《PackageManagerService 钻研(4)- PackageInstaller》

三、IPackageManager

3.1 ActivityThread

在上面分析 ContextImplgetPackageManager() 方法的时候,我们看到如下源码(回顾):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// frameworks/base/core/java/android/app/ContextImpl.java

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

这边,我们重点看下 ActivityThread 的静态方法 getPackageManager()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public final class ActivityThread extends ClientTransactionHandler {
... ...

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

3.2 ApplicationPackageManager

再回顾下 ApplicationPackageManager 的构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
public class ApplicationPackageManager extends PackageManager {
... ...

private final ContextImpl mContext;
private final IPackageManager mPM;

protected ApplicationPackageManager(ContextImpl context, IPackageManager pm) {
mContext = context;
mPM = pm;
}
... ...
}

3.3 IPackageManager

IPackageManager.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface IPackageManager extends android.os.IInterface {
/** Local-side IPC implementation stub class. */
// 定义内部类 Stub,派生自 Binder,实现 IPackageManager 接口
public static abstract class Stub extends android.os.Binder
implements android.content.pm.IPackageManager {
private static final java.lang.String DESCRIPTOR =
"android.content.pm.IPackageManager";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
... ...

// 定义 Stub 的内部类 Proxy,实现 IPackageManager 接口
private static class Proxy implements android.content.pm.IPackageManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
... ...
}
... ...
}

所以在 ApplicationPackageManager 里面的 mPM 其实就是 IPackageManager.Stub 内部类 Proxy 对象

那对应的 IPackageManager.Stub 是什么?其实就是 PackageManagerService.java

1
public class PackageManagerService extends IPackageManager.Stub implements PackageSender {

3.4 小结

结合上面的分析,再结合 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。