浅析PackageManager的工作流程

我们在使用PackageManager的时候,一般都是直接获取到PackageManager对象,然后就直接调用它的函数进行相应操作,但它内部究竟是怎样工作的呢?其实它内部获取的是远程服务,真正调用的都是服务中的操作。
我们这里仅仅停留在java层进行讨论,没有深入到底层C/C++实现。

在PackageManager的说明中有这样一段话:

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

从中我们可以大致知道两点:
1、作用:通过这个类我们可以获取安装在设备上的应用程序包相关的各种信息。
2、创建:通过Context的getPackageManager函数可以得到这个对象。
但是进入Context这个类,你可能会有些失望,因为Context是一个抽象类,它根本没有实现这个函数,其实失望的不止这个,当你查看PackageManager类的时候,你发现它也是也是一个抽象类,它里面的函数也没有实现。
重新梳理一些,既然Context类找不到实现,那么我们就看它的子类,Context有一个实现类,其实很多用到Context对象的类,它实际引用的都是它的实现类对象,这个类就是ContextImpl,进入这个类就可以看到实现了,直接看getPackageManager函数:

class ContextImpl extends Context {
    private PackageManager mPackageManager;

    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        //这里会得到PackageManager服务的本地代理对象pm
        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            //这里会将这个本地代理对象包装到ApplicationPackageManager中
            //其实在ApplicationPackageManager源码中也可以看到,
            //调用ApplicationPackageManager的方法本质执行的还是pm的方法
            //这样就可以理解ApplicationPackageManager代码是怎么回事了
            //另外ApplicationPackageManager是PackageManager的子类。
            //我们所操作的都是这个类,在Context的getPackageManager中我们得到的也是这个类的对象。
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }
}

我们知道,我们在获取到远程服务的本地代理对象之后,就可以直接通过本地代理对象来调用远程服务的函数,所以上面在获取到PackageManager服务的本地代理对象之后,它把这个对象包装到了ApplicationPackageManager中,但是从ApplicationPackageManager源码中也可以看到,调用ApplicationPackageManager的方法本质执行的还是代理对象的方法。上面的注释说的比较明白,要仔细看看。

那么这个PackageManager服务的本地代理对象是如何得到的呢?直接看ActivityThread.getPackageManager()函数源码:

    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        //获取PacakgeManager的远程服务的IBinder对象。
        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;
    }

首先我们需要弄清楚Client、Server和Service Manager的相互关系:
Service Manager在Binder机制中既充当守护进程的角色,同时它也充当着Server角色,然而它又与一般的Server不一样。对于普通的Server来说,Client如果想要获得Server的远程接口,那么必须通过Service Manager远程接口提供的getService接口来获得,这本身就是一个使用Binder机制来进行进程间通信的过程。而对于Service Manager这个Server来说,Client如果想要获得Service Manager远程接口,却不必通过进程间通信机制来获得,因为Service Manager远程接口是一个特殊的Binder引用,它的引用句柄一定是0。

通过上面的解释,我们就知道ServiceManager.getService(“package”)要获取远程的服务,首先要获得Service Manager远程接口,然后通过Service Manager远程接口提供的getService接口来获得。
下面我们直接看实现代码:

public final class ServiceManager {
    private static final String TAG = "ServiceManager";

    private static IServiceManager sServiceManager;
    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        //它的作用就是得到ServiceManager远程接口
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                //获取ServiceManager远程接口,然后得到指定服务
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
}

最终通过ServiceManager远程接口调用getService获取到PackageManager的IBinder对象。回到上面的getPackageManager函数,获取到PackageManager的IBinder对象之后,就通过IPackageManager.Stub.asInterface(b)得到它的服务代理对象。接着回到最上面,基本就可以知道PackageManager是如何得到,我们操作的是它的子类ApplicationPackageManager,本质操作的实际是远程服务的方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值