PMS系列:
1、本文PackageManagerService服务框架详解
2、PackageManagerService启动分析
3、PackageManagerService之app数据类(Settings)分析
4、PackageManagerService扫描安装apk详解
5、PackageManagerService根据权限等级管理权限(默认赋予apk权限)
framework层给我们提供了很多服务例如ActivityManager、WnidowManager、PackageManager等等,这些服务的框架都比较类似,刚好最近在阅读PMS服务相关的代码,这里对PackageManger的框架进行一个总结。先来一张图。
结构
这张图清晰的描述了PackageManager的框架。是一种标准的Service(服务端)-client(客户端)结构
这里简单说一下service-client
service:提代理类proxy给client调用,所有动作的具体实现都是在service中进行;
client:获得service的proxy实现调用;
图中client主要是PackageManager,ApplicationManager,其余都是服务端
本文讲述主要涉猎代码如下
Service:
frameworks/base/core/java/android/content/pm/IPackageManager.aidl
out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/content/pm/IPackageManager.java
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
Client:
frameworks/base/core/java/android/content/pm/PackageManager.java
frameworks/base/core/java/android/app/ApplicationPackageManager.java
理解PackageManager的框架实际就是理解aidl这种进程间的通信方式。
客户端
PackageManager是一个抽象类,里边主要是一些抽象方法,以getPackageInfo为例子,讲述client如何调用
public abstract class PackageManager {
...//三个点代表省略部分代码
public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
throws NameNotFoundException;
@RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
public abstract PackageInfo getPackageInfoAsUser(String packageName,
@PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
...
}
我们对PackageManager的调用是上下文ContextImpl.java中Context.getPackageManager():
@Override
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
这里返回的是ApplicationPackageManager,因为PackageManager是一个抽象类,它需要一个具体的实现,所以这里ApplicationPackageManager继承自PackageManager,代码片段如下:
public class ApplicationPackageManager extends PackageManager {
private final IPackageManager mPM;
ApplicationPackageManager(ContextImpl context,
IPackageManager pm) {
mContext = context;
mPM = pm;
}
...
@Override
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
return getPackageInfoAsUser(packageName, flags, mContext.getUserId());
}
@Override
public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId);
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
throw new NameNotFoundException(packageName);
}
...
}
1、从ApplicationPackageManager的实现代码可以明确的看出,我们调用getPackageInfo实际上最后调用的是mPM.getPackageInfo(packageName, flags, userId)这里的mPM就是getPackageManager方法中带入的IPackageManager。
2、这个方法比较关键,从前面什么是service代码和什么是clent代码的分类中,我们知道IPackageManager这个是服务端提供的类
我们来看下ActivityThread.getPackageManager()这个方法:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
//Slog.v("PackageManager", "returning cur default = " + sPackageManager);
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
//Slog.v("PackageManager", "default service binder = " + b);
sPackageManager = IPackageManager.Stub.asInterface(b);
//Slog.v("PackageManager", "default service = " + sPackageManager);
return sPackageManager;
}
1、这里的调用依赖android的Binder机制,实现进程之间的调用
2、ServiceManager.getService("package")得到的其实是PackageManagerService
3、然后调用IPackageManager.Stub.asInterface(b),得到IPackageManager的内部类,即代理类Proxy:IPackageManager.Stub.Proxy,所以得到的就是PackageManagerService的代理类
4、那么最后实际上是调用到了proxy.getPackageInfo方法,
5、这里的代码对aidl通信方式不熟悉的人看着可能会有点儿费解,这个方法调用到服务端了,我会在后面服务端解析中详细说明这个方法;
客户端的流程就分析到此,我们知道client的主要作用就是获得service的proxy来实现调用,最终实现就是获得proxy,下面我们进行服务端的代码分析:
服务端
在接着分析上文proxy.getPackageInfo之前,我们先分析一下service端是如何构成的
IPackageManager
服务端的定义是从IpackageManager.aidl文件开始的,接口IpackageManager.aidl中只定义了相关方法,代码片段:
interface IPackageManager {
...
PackageInfo getPackageInfo(String packageName, int flags, int userId);
int getPackageUid(String packageName, int flags, int userId);
int[] getPackageGids(String packageName, int flags, int userId);
...
}
android的编译会识别aidl的文件,aidl方式其实就是一种进程间通过Binder通信的方式,在编译的时候跟对aidl自动生成一个对应的java文件,这里生成的是IpackageManager.java文件,这也是为啥IpackageManager.java的路径是在out目录下的原因,没有编译工程之前是没有IpackageManager.java这个文件的。生成的IpackageManager.java这个文件对应图中的IpackageManager,我们来看看IpackageManager的构成,把IpackageManager.java的构成记在心里,基本也能理解aidl是怎么实现进程之间的通信的,IpackageManager.java代码片段如下:
public interface IPackageManager extends android.os.IInterface{
//IPackageManager中定义的类Stub,Stub集成自Binder,并实现IPackageManager.aidl中定义的接口
public static abstract class Stub extends android.os.Binder implements android.content.pm.IPackageManager{
...
public static android.content.pm.IPackageManager asInterface(android.os.IBinder obj){
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//如果是当前进程,返回的是IPackageManager本身
if (((iin!=null)&&(iin instanceof android.content.pm.IPackageManager))) {
return ((android.content.pm.IPackageManager)iin);
}
//不是当前进程,返回的是代理类
return new android.content.pm.IPackageManager.Stub.Proxy(obj);
}
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
...
switch (code) {
case TRANSACTION_getPackageInfo:{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
int _arg1;
_arg1 = data.readInt();
int _arg2;
_arg2 = data.readInt();
android.content.pm.PackageInfo _result = this.getPackageInfo(_arg0, _arg1, _arg2);
reply.writeNoException();
if ((_result!=null)) {
reply.writeInt(1);
_result.writeToParcel(reply, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
...//类似的case方法很多,这里只举例case TRANSACTION_getPackageInfo,其他代码省略
}
...
}
...
//类Stub中定义的代理类Proxy,Proxy中代理方法很多,这里同样只贴出了getPackageInfo方法
private static class Proxy implements android.content.pm.IPackageManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
...
@Override
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
android.content.pm.PackageInfo _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(packageName);
_data.writeInt(flags);
_data.writeInt(userId);
mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);
_reply.readException();
if ((0!=_reply.readInt())) {
_result = android.content.pm.PackageInfo.CREATOR.createFromParcel(_reply);
} else {
_result = null;
}
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
...
}
...
//这里的函数就是Stub实现的接口implements android.content.pm.IPackageManager,只列出来三个,别的都省略,继承接口方法必须全部实现,否则会报错
public void checkPackageStartable(java.lang.String packageName, int userId) throws android.os.RemoteException;
public boolean isPackageAvailable(java.lang.String packageName, int userId) throws android.os.RemoteException;
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException;
...
}
IpackageManager.java的理解主要分为三点:
1、IpackageManager.java中定义一个Stub类,这个类实现了IPackageManager.aidl中定义的接口;
2、代理类Proxy:IpackageManager.Stub.Proxy,Proxy中的方法供client调用;
3、调用Proxy中的方法其实就是间接调用了Stub中的onTransact方法,在onTransact中最终调用了Stub实现的接口方法;
我们接着客户端的代码接着分析,以实例来说明调用:
1、客户端调用实际是Proxy.getPackageInfo;
2、Proxy.getPackageInfo方法中调用mRemote.transact(Stub.TRANSACTION_getPackageInfo, _data, _reply, 0);
3、Stub.transact中android.content.pm.PackageInfo _result = this.getPackageInfo(_arg0, _arg1, _arg2);
4、this.getPackageInfo其实就是Stub实现的IPackageManager接口中的getPackageInfo方法,即:
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException;
那么现在看来方法调用现在是调用到了IPackageManager.java中Stub类中实现的接口getPackageInfo那么,我们接下来讲具体的实现PackageManagerService.java
PackageManagerservice
PMS的代码很长,这里只列举小部分
public class PackageManagerService extends IPackageManager.Stub {
...
public static PackageManagerService main(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
//创建PackageManagerService
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
// Disable any carrier apps. We do this very early in boot to prevent the apps from being
// disabled after already being started.
CarrierAppUtils.disableCarrierAppsUntilPrivileged(context.getOpPackageName(), m,
UserHandle.USER_SYSTEM);
//创建完成后把PMS加入到ServiceManager中
ServiceManager.addService("package", m);
return m;
}
...
@Override
public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
enforceCrossUserPermission(Binder.getCallingUid(), userId,
false /* requireFullPermission */, false /* checkShell */, "get package info");
// reader
synchronized (mPackages) {
final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0;
PackageParser.Package p = null;
if (matchFactoryOnly) {
final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName);
if (ps != null) {
return generatePackageInfo(ps, flags, userId);
}
}
if (p == null) {
p = mPackages.get(packageName);
if (matchFactoryOnly && p != null && !isSystemApp(p)) {
return null;
}
}
if (DEBUG_PACKAGE_INFO)
Log.v(TAG, "getPackageInfo " + packageName + ": " + p);
if (p != null) {
return generatePackageInfo((PackageSetting)p.mExtras, flags, userId);
}
if (!matchFactoryOnly && (flags & MATCH_UNINSTALLED_PACKAGES) != 0) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
return generatePackageInfo(ps, flags, userId);
}
}
return null;
}
}
我们来分析这个代码片段:
1、第一点也是最关键的一点,PackageManagerService继承IPackageManager.Stub类,而IPackageManager.Stub类继承自Binder实现IpackageManager接口
2、这里请上翻看客户端中讲的最后个方法ActivityThread.getPackageManager(),这个方法中先是获得Binder实例:IBinder b = ServiceManager.getService("package")然后通过binder实例获得代理类Proxy
3、我们看服务端代码,在PMS创建完成后就添加到了ServiceManager中:ServiceManager.addService("package", m);所以2中实际得到的是PMS的Binder类型实例,然后得到PMS的代理类
4、接着上面的getPackageInfo方法,调用到Stub中的getPackageInfo接口方法,PackageManagerService则是接口方法getPackageInfo的实现,所以最终方法是调用到了PackageManagerService.getPackageInfo
总结
PackageManager的框架就是一个Service-client结构
Service: IPackageManager.aidl - IPackageManager.java - PackageManagerService.java
client: PackageManager.java - ApplicationPackageManager
把服务端的一个流向记住,你就完全能掌握PMS的框架结构了。
Read the fucking sources code!
网友评论