当前位置:   article > 正文

Android getSystemService原理

android getsystemservice

前言

  • 下面会把getSystemService简称为GSS

为什么我需要搞清楚getSystemService的原理?
在分析源码时错误的把GSS以为是基于binder实现的,但发现打印的日志内容与我所设想的不一样,按理来说audioService调用Binder.getCallingPid()时应该返回获取到的audioManager的pid,因为是从audioManager通过binder调用到的audioService的。但实际打印确实上层应用的,然后看到AudioManager的constructor有Context参数,后面才发现自己望文生义了,GSS返回的是实例类对象,不是一个独立进程的binder。

先给个结论。对于缓存类的系统服务(大部分情况),会通过map根据服务名称返回实例对象,第一次获取时才真正创建对象,后面获取时都是返回缓存。真正做这工作的在SystemServiceRegistry.java中,其中处理多线程并发获取服务实例的过程很精妙。

        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            final int[] gates = ctx.mServiceInitializationStateArray;

            for (;;) {
                boolean doInitialize = false;
                synchronized (cache) {
                    // Return it if we already have a cached instance.
                    T service = (T) cache[mCacheIndex];
                    if (service != null || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                        return service;
                    }

                    // If we get here, there's no cached instance.

                    // Grr... if gate is STATE_READY, then this means we initialized the service
                    // once but someone cleared it.
                    // We start over from STATE_UNINITIALIZED.
                    if (gates[mCacheIndex] == ContextImpl.STATE_READY) {
                        gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
                    }

                    // It's possible for multiple threads to get here at the same time, so
                    // use the "gate" to make sure only the first thread will call createService().

                    // At this point, the gate must be either UNINITIALIZED or INITIALIZING.
                    if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
                        doInitialize = true;
                        gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
                    }
                }

                if (doInitialize) {
                    // Only the first thread gets here.

                    T service = null;
                    @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
                    try {
                        // This thread is the first one to get here. Instantiate the service
                        // *without* the cache lock held.
                        service = createService(ctx);
                        newState = ContextImpl.STATE_READY;

                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);

                    } finally {
                        synchronized (cache) {
                            cache[mCacheIndex] = service;
                            gates[mCacheIndex] = newState;
                            cache.notifyAll();
                        }
                    }
                    return service;
                }
                // The other threads will wait for the first thread to call notifyAll(),
                // and go back to the top and retry.
                synchronized (cache) {
                    while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
                        try {
                            cache.wait();
                        } catch (InterruptedException e) {
                            Log.w(TAG, "getService() interrupted");
                            Thread.currentThread().interrupt();
                            return null;
                        }
                    }
                }
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70

调用链为:
首先mainActivity调用到的是继承的父类Activity的GSS。

  1. Activity.getSystemService(),这一步过滤服务名WINDOW_SERVICE或者SEARCH_SERVICE,这两个特殊服务可以直接返回。
if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. ContextThemeWrapper.getSystemService(),这一步过滤掉服务LAYOUT_INFLATER_SERVICE,他的处理其实和下一步差不多,但是返回的服务会再调用一下cloneInContext(this),不理解为什么这个服务要特殊处理这一下。
mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
  • 1

下一步会调用到保存的mBase,这个参数是ContextThemeWrapper构造时传递的,估计是activity时就创建好了,但具体怎么传递context、哪里地方、什么时候创建的暂时不清楚。context是一个abstract class,他的实现类是contextImpl。

  1. contextImpl.getSystemService()。这一步只是转给SystemServiceRegistry处理
return SystemServiceRegistry.getSystemService(this, name);```
  • 1
  1. SystemServiceRegistry.getSystemService()。这里会从hashMap SYSTEM_SERVICE_FETCHERS根据服务名取出一个叫做ServiceFetcher的东西,然后由fetcher负责获取服务实例。

ServiceFetcher就是一个接口,实现该接口需要实现getService函数

static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
  • 1
  • 2
  • 3

关于这个hashmap,SYSTEM_SERVICE_FETCHERS是在SystemServiceRegistry实例化是初始化的,也就是在该类的static语句块中。这一步注册很多服务。

static {
	......
	registerService(Context.AUDIO_SERVICE, AudioManager.class,
                new CachedServiceFetcher<AudioManager>() {
            @Override
            public AudioManager createService(ContextImpl ctx) {
                return new AudioManager(ctx);
            }});
    ......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

registerSerivce只是一个put元素进hashmap的封装,把服务名和一个CachedServiceFetcher的类对象扔进去。可以猜到CachedServiceFetcher实现了ServiceFetcher

CachedServiceFetcher() {
            // Note this class must be instantiated only by the static initializer of the
            // outer class (SystemServiceRegistry), which already does the synchronization,
            // so bare access to sServiceCacheSize is okay here.
            mCacheIndex = sServiceCacheSize++;
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这是该类的构造函数,需要解释一下,所以缓存的服务实例对象是存储在context的cached数组中的,另外一个int类型数组gates是表示缓存的每一个服务实例对象的当前状态,因此mCacheIndex就是存储的这个fetcher所指服务实例对象在cached数组中的索引。注释解释了为什么不用给sServiceCacheSize加锁。

从开头的实例过程可以看出,每一个服务对象都是lazy initialized,因此可以加快activity的启动速度(我的理解),并且避免了实例化一些并不需要的服务对象,只在真正需要的时候才会实例化。
另外实例化过程还涉及到了多线程的race condition情况的处理,解决的很巧妙(对我这个菜鸟而言)。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/588995
推荐阅读
相关标签
  

闽ICP备14008679号