PackageManagerService服务框架详解

PMS系列:
1、本文PackageManagerService服务框架详解
2、PackageManagerService启动分析
3、PackageManagerService之app数据类(Settings)分析
4、PackageManagerService扫描安装apk详解
5、PackageManagerService根据权限等级管理权限(默认赋予apk权限)

framework层给我们提供了很多服务例如ActivityManager、WnidowManager、PackageManager等等,这些服务的框架都比较类似,刚好最近在阅读PMS服务相关的代码,这里对PackageManger的框架进行一个总结。先来一张图。

《PackageManagerService服务框架详解》

结构

这张图清晰的描述了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!

    原文作者:Yink_Liu
    原文地址: https://www.jianshu.com/p/ef058fcfcd30
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞