关于Android P上getSystemService()的更改

问题阐述:

由某个系统service创建出来的对象,并用的这个对象通过getSystemService()函数去获取对应Service,发现总是为null。

解决办法

去SystemServer里面review你的逻辑,看看是否有对应service未起来的时候就通过getSystemService去获取了,这样会导致当前context的cache里面记录STATE_NOT_FOUND的flag,那么自此之后即使后来service起来了此Context也不会拿到这个service。

探索:

一般上述问题的出现是在对应service没起来的时候就去获取了,当然得不到,但是研究表明,此时的service已经起来,并不是这个的问题。
我们一般获取service都是通过context.getSystemService的,那我们看一下调用逻辑:

getSystemService() 

-->

public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
 }

-->

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];
                    
                    //从服务缓存中获取,如果有则返回,如果状态为STATE_NOT_FOUND则返回null
                    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.
                    // 缓存中没有找到服务实例,但是其状态是 STATE_READY,说明有可能是缓存中
                    // 的服务实例被清除了,只是状态没有更新而已,此时需要更新状态并重新创建。
                    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.
                    / 更新服务状态为 STATE_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
                        service = createService(ctx);
                        newState = ContextImpl.STATE_READY;

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

                    } finally {
                        // 把服务实例和服务状态保存到缓存中去,有两种可能:
                        // 1. 服务创建成功时,把创建的服务实例和状态 STATE_READY 分别缓存起来;
                        // 2. 服务创建失败时,把 null 和状态 STATE_NOT_FOUND 分别缓存起来。
                        // 在后续查询缓存的过程中,只要是这两种情况就直接返回不再进行创建。
                        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;
                        }
                    }
                }
            }
        }

以上就为Android P的获取逻辑,关键在于getService里面mCacheIndex的作用,及每一个Context里面都会把system里面所有的service的状态存在mCacheIndex的数组里面,值如下:

    static final int STATE_UNINITIALIZED = 0;
    static final int STATE_INITIALIZING = 1;
    static final int STATE_READY = 2;
    static final int STATE_NOT_FOUND = 3;

按照P上的逻辑,未create的状态为STATE_UNINITIALIZED,create过称中service没起来(其实也可以看作是没有这个service)为STATE_NOT_FOUND。那么在这个Context里面当一个service的flag被标志成STATE_NOT_FOUND,那么之后无论这个service起来与否,通过getSystemService()是得不到这个service的
O上的就有些许的差别,代码如下:

public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                if (service == null) {
                    try {
                        service = createService(ctx);
                        cache[mCacheIndex] = service;
                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);
                    }
                }
                return (T)service;
            }
        }

如上,它只会抛一个异常,每次调用如果chche里面没有,都会去create service。所以,在O上即使getSystemService的时候对应service没起来,也可以等后期起来的时候重新获得。

猜你喜欢

转载自blog.csdn.net/qq_33717425/article/details/95308624