getSystemService的奇怪问题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dingjikerbo/article/details/67644806

先看如下代码,这两个PowerManager不是同一个对象,不过其核心都是同一个Proxy Binder,只是外面批了不同的马甲而已。

PowerManager manager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager manager2 = (PowerManager)getApplicationContext().getSystemService(POWER_SERVICE);

我们先用如下代码测试一下,这里通过反射拿到PowerManager中的IPowerManager对象,然后通过asBinder拿到背后的Proxy Binder。

private void testPowerManager() throws Exception {
        Class<?> clazz = Class.forName("android.os.IPowerManager");
        Method method = MethodUtils.getAccessibleMethod(clazz, "asBinder");

        PowerManager manager1 = (PowerManager) getSystemService(POWER_SERVICE);
        Object object1 = FieldUtils.getField(PowerManager.class, "mService", true).get(manager1);
        IBinder binder1 = (IBinder) method.invoke(object1);
        LogUtils.v(String.format("manager1 = %s, object1 = %s, binder1 = %s", manager1, object1, binder1));

        PowerManager manager2 = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);
        Object object2 = FieldUtils.getField(PowerManager.class, "mService", true).get(manager2);
        IBinder binder2 = (IBinder) method.invoke(object2);
        LogUtils.v(String.format("manager2 = %s, object2 = %s, binder2 = %s", manager2, object2, binder2));
    }

打印的结果如下:

V: manager1 = android.os.PowerManager@42845168, object1 = android.os.IPowerManager$Stub$Proxy@42845158, binder1 = android.os.BinderProxy@428450f8
V: manager2 = android.os.PowerManager@42846078, object2 = android.os.IPowerManager$Stub$Proxy@42846068, binder2 = android.os.BinderProxy@428450f8

可见尽管PowerManager和IPowerManager都不同,但是最后的binder1和binder2是同一个对象。

为什么这两个getSystemService返回的不同呢?只能从内核源码中找答案了,这里不论Activity还是Application,其Context实现都在ContextImpl中,我们查看getSystemService实现,如下:

@Override
public Object getSystemService(String name) {
    ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
    return fetcher == null ? null : fetcher.getService(this);
}

这里是从一个全局Cache中取出ServiceFetcher,然后调用getService。这个ServiceFetcher定义如下:

static class ServiceFetcher {
    int mContextCacheIndex = -1;

    public Object getService(ContextImpl ctx) {
        ArrayList<Object> cache = ctx.mServiceCache;
        Object service;

        synchronized (cache) {
            service = cache.get(mContextCacheIndex);
            if (service != null) {
                return service;
            }
            service = createService(ctx);
            cache.set(mContextCacheIndex, service);
            return service;
        }
    }
}

可见,每个ContextImpl中有一个mServiceCache,每次getService都先到该cache中查找,查找不到时才调用createService创建一个。而Activity和Application的ContextImpl不是同一个,所以这里的mServiceCache自然也不是同一个。

关于Activity和Application的创建主要在ActivityThread的performLaunchActivity中,如下:

Application app = r.packageInfo.makeApplication(false, mInstrumentation);

Context appContext = createBaseContextForActivity(r, activity);

activity.attach(appContext, this, getInstrumentation(), r.token,
        r.ident, app, r.intent, r.activityInfo, title, r.parent,
        r.embeddedID, r.lastNonConfigurationInstances, config);

Application的Context在LoadedApk的makeApplication中创建的,Activity的Context是createBaseContextForActivity中创建的,两个不是同一个Context。

为什么这里要分成两个Context呢,这个问题值得回味……

展开阅读全文

没有更多推荐了,返回首页