PMS系列:
1、本文PackageManagerService服務(wù)框架詳解
2、PackageManagerService啟動分析
3、PackageManagerService之a(chǎn)pp數(shù)據(jù)類(Settings)分析
4、PackageManagerService掃描安裝apk詳解
5、PackageManagerService根據(jù)權(quán)限等級管理權(quán)限(默認(rèn)賦予apk權(quán)限)
framework層給我們提供了很多服務(wù)例如ActivityManager、WnidowManager、PackageManager等等,這些服務(wù)的框架都比較類似,剛好最近在閱讀PMS服務(wù)相關(guān)的代碼,這里對PackageManger的框架進(jìn)行一個總結(jié)。先來一張圖。
結(jié)構(gòu)
這張圖清晰的描述了PackageManager的框架。是一種標(biāo)準(zhǔn)的Service(服務(wù)端)-client(客戶端)結(jié)構(gòu)
這里簡單說一下service-client
service:提代理類proxy給client調(diào)用,所有動作的具體實現(xiàn)都是在service中進(jìn)行;
client:獲得service的proxy實現(xiàn)調(diào)用;
圖中client主要是PackageManager,ApplicationManager,其余都是服務(wù)端
本文講述主要涉獵代碼如下
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這種進(jìn)程間的通信方式。
客戶端
PackageManager是一個抽象類,里邊主要是一些抽象方法,以getPackageInfo為例子,講述client如何調(diào)用
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的調(diào)用是上下文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是一個抽象類,它需要一個具體的實現(xiàn),所以這里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的實現(xiàn)代碼可以明確的看出,我們調(diào)用getPackageInfo實際上最后調(diào)用的是mPM.getPackageInfo(packageName, flags, userId)這里的mPM就是getPackageManager方法中帶入的IPackageManager。
2、這個方法比較關(guān)鍵,從前面什么是service代碼和什么是clent代碼的分類中,我們知道IPackageManager這個是服務(wù)端提供的類
我們來看下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、這里的調(diào)用依賴android的Binder機(jī)制,實現(xiàn)進(jìn)程之間的調(diào)用
2、ServiceManager.getService("package")得到的其實是PackageManagerService
3、然后調(diào)用IPackageManager.Stub.asInterface(b),得到IPackageManager的內(nèi)部類,即代理類Proxy:IPackageManager.Stub.Proxy,所以得到的就是PackageManagerService的代理類
4、那么最后實際上是調(diào)用到了proxy.getPackageInfo方法,
5、這里的代碼對aidl通信方式不熟悉的人看著可能會有點兒費解,這個方法調(diào)用到服務(wù)端了,我會在后面服務(wù)端解析中詳細(xì)說明這個方法;
客戶端的流程就分析到此,我們知道client的主要作用就是獲得service的proxy來實現(xiàn)調(diào)用,最終實現(xiàn)就是獲得proxy,下面我們進(jìn)行服務(wù)端的代碼分析:
服務(wù)端
在接著分析上文proxy.getPackageInfo之前,我們先分析一下service端是如何構(gòu)成的
IPackageManager
服務(wù)端的定義是從IpackageManager.aidl文件開始的,接口IpackageManager.aidl中只定義了相關(guān)方法,代碼片段:
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方式其實就是一種進(jìn)程間通過Binder通信的方式,在編譯的時候跟對aidl自動生成一個對應(yīng)的java文件,這里生成的是IpackageManager.java文件,這也是為啥IpackageManager.java的路徑是在out目錄下的原因,沒有編譯工程之前是沒有IpackageManager.java這個文件的。生成的IpackageManager.java這個文件對應(yīng)圖中的IpackageManager,我們來看看IpackageManager的構(gòu)成,把IpackageManager.java的構(gòu)成記在心里,基本也能理解aidl是怎么實現(xiàn)進(jìn)程之間的通信的,IpackageManager.java代碼片段如下:
public interface IPackageManager extends android.os.IInterface{
//IPackageManager中定義的類Stub,Stub集成自Binder,并實現(xiàn)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);
//如果是當(dāng)前進(jìn)程,返回的是IPackageManager本身
if (((iin!=null)&&(iin instanceof android.content.pm.IPackageManager))) {
return ((android.content.pm.IPackageManager)iin);
}
//不是當(dāng)前進(jìn)程,返回的是代理類
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;
}
...
}
...
//這里的函數(shù)就是Stub實現(xiàn)的接口implements android.content.pm.IPackageManager,只列出來三個,別的都省略,繼承接口方法必須全部實現(xiàn),否則會報錯
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類,這個類實現(xiàn)了IPackageManager.aidl中定義的接口;
2、代理類Proxy:IpackageManager.Stub.Proxy,Proxy中的方法供client調(diào)用;
3、調(diào)用Proxy中的方法其實就是間接調(diào)用了Stub中的onTransact方法,在onTransact中最終調(diào)用了Stub實現(xiàn)的接口方法;
我們接著客戶端的代碼接著分析,以實例來說明調(diào)用:
1、客戶端調(diào)用實際是Proxy.getPackageInfo;
2、Proxy.getPackageInfo方法中調(diào)用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實現(xiàn)的IPackageManager接口中的getPackageInfo方法,即:
public android.content.pm.PackageInfo getPackageInfo(java.lang.String packageName, int flags, int userId) throws android.os.RemoteException;
那么現(xiàn)在看來方法調(diào)用現(xiàn)在是調(diào)用到了IPackageManager.java中Stub類中實現(xiàn)的接口getPackageInfo那么,我們接下來講具體的實現(xiàn)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();
//創(chuàng)建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);
//創(chuàng)建完成后把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、第一點也是最關(guān)鍵的一點,PackageManagerService繼承IPackageManager.Stub類,而IPackageManager.Stub類繼承自Binder實現(xiàn)IpackageManager接口
2、這里請上翻看客戶端中講的最后個方法ActivityThread.getPackageManager(),這個方法中先是獲得Binder實例:IBinder b = ServiceManager.getService("package")然后通過binder實例獲得代理類Proxy
3、我們看服務(wù)端代碼,在PMS創(chuàng)建完成后就添加到了ServiceManager中:ServiceManager.addService("package", m);所以2中實際得到的是PMS的Binder類型實例,然后得到PMS的代理類
4、接著上面的getPackageInfo方法,調(diào)用到Stub中的getPackageInfo接口方法,PackageManagerService則是接口方法getPackageInfo的實現(xiàn),所以最終方法是調(diào)用到了PackageManagerService.getPackageInfo
總結(jié)
PackageManager的框架就是一個Service-client結(jié)構(gòu)
Service: IPackageManager.aidl - IPackageManager.java - PackageManagerService.java
client: PackageManager.java - ApplicationPackageManager
把服務(wù)端的一個流向記住,你就完全能掌握PMS的框架結(jié)構(gòu)了。
Read the fucking sources code!