PackageManagerService服務(wù)框架詳解

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!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容