简单跟踪一下getSystemService()

Android  源码分析  2024年3月22日 pm5:55发布8个月前更新 91es.com站长
82 0 0

前言

记录一下getSystemService()获取的源码流程,加深一下印象。

正文

这里以获取AudioManager为例

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

getSystemService()定义在Context.java中

public static final String AUDIO_SERVICE = "audio";

Context.java

frameworks\base\core\java\android\content\Context.java
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);

抽象方法。

Context的实现类是ContextImpl,具体看ContextImpl.java

ContextImpl.java

\frameworks\base\core\java\android\app\ContextImpl.java
@Override
public Object getSystemService(String name) {
    if (vmIncorrectContextUseEnabled()) {
        //略
    }
    //重点关注后面的
    return SystemServiceRegistry.getSystemService(this, name);
}

SystemServiceRegistry.java

\frameworks\base\core\java\android\app\SystemServiceRegistry.java

我们一开始传入的name是Context.AUDIO_SERVICE,也就是audio。

public static Object getSystemService(ContextImpl ctx, String name) {
    //不为null
    if (name == null) {
        return null;
    }
    //SYSTEM_SERVICE_FETCHERS是map,存储了服务相关信息
    final ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
    if (fetcher == null) {
        if (sEnableServiceNotFoundWtf) {
            Slog.wtf(TAG, "Unknown manager requested: " + name);
        }
        return null;
    }
    //获取服务,这里需要重点关注fetcher
    final Object ret = fetcher.getService(ctx);
    if (sEnableServiceNotFoundWtf && ret == null) {
        // Some services do return null in certain situations, so don't do WTF for them.
        switch (name) {
            case Context.CONTENT_CAPTURE_MANAGER_SERVICE:
            case Context.APP_PREDICTION_SERVICE:
            case Context.INCREMENTAL_SERVICE:
            case Context.ETHERNET_SERVICE:
                return null;
        }
        return null;
    }
    return ret;
}

上面重点关注的是SYSTEM_SERVICE_FETCHERS和ServiceFetcher。

SYSTEM_SERVICE_FETCHERS
 private static final Map<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new ArrayMap<String, ServiceFetcher<?>>();

具体看哪里添加的

registerService
//私有的静态变量,类内部使用
private static <T> void registerService(@NonNull String serviceName,
        @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher) {
    SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
    //这里添加的
    SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
}

这里有多个map存储服务相关信息,我们这里值关注SYSTEM_SERVICE_FETCHERS。

第一个是服务名,第二个是serviceFetcher。

在SystemServiceRegistry中有一个静态代码块,这里注册了

Context.ACTIVITY_SERVICE
Context.AUDIO_SERVICE
Context.ACCOUNT_SERVICE
Context.ACCESSIBILITY_SERVICE
Context.HDMI_CONTROL_SERVICE
等

这里只关注AUDIO_SERVICE的注册。

static{
	//略
	registerService(Context.AUDIO_SERVICE, AudioManager.class,
        new CachedServiceFetcher<AudioManager>() {
    @Override
    public AudioManager createService(ContextImpl ctx) {
        return new AudioManager(ctx);
    }});
	//略
}

第三个是匿名创建CachedServiceFetcher

CachedServiceFetcher
static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
    private final int mCacheIndex;

    CachedServiceFetcher() {
        mCacheIndex = sServiceCacheSize++;
    }

    @Override
    @SuppressWarnings("unchecked")
    public final T getService(ContextImpl ctx) {
        final Object[] cache = ctx.mServiceCache;
        final int[] gates = ctx.mServiceInitializationStateArray;
        boolean interrupted = false;
        T ret = null;
		//循环,知道获取成功就退出
        for (;;) {
            boolean doInitialize = false;
            synchronized (cache) {
				//如果存在缓存,就返回
                T service = (T) cache[mCacheIndex];
                if (service != null) {
                    ret = service;
                    break; // exit the for (;;)
                }
                if (gates[mCacheIndex] == ContextImpl.STATE_READY
                        || gates[mCacheIndex] == ContextImpl.STATE_NOT_FOUND) {
                    gates[mCacheIndex] = ContextImpl.STATE_UNINITIALIZED;
                }
                if (gates[mCacheIndex] == ContextImpl.STATE_UNINITIALIZED) {
                    doInitialize = true;
                    gates[mCacheIndex] = ContextImpl.STATE_INITIALIZING;
                }
            }
            if (doInitialize) {
                T service = null;
                @ServiceInitializationState int newState = ContextImpl.STATE_NOT_FOUND;
                try {
                    service = createService(ctx);
                    newState = ContextImpl.STATE_READY;

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

                } finally {
                    synchronized (cache) {
                        cache[mCacheIndex] = service;
                        gates[mCacheIndex] = newState;
                        cache.notifyAll();
                    }
                }
                ret = service;
                break;
            }
            synchronized (cache) {
                while (gates[mCacheIndex] < ContextImpl.STATE_READY) {
                    try {
                        interrupted |= Thread.interrupted();
                        cache.wait();
                    } catch (InterruptedException e) {
                        interrupted = true;
                    }
                }
            }
        }
        if (interrupted) {
            Thread.currentThread().interrupt();
        }
        return ret;
    }

    public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
}

上面代码很多,但最重要的是需要重写的createService()。

因此回到上面第三个参数创建匿名CachedServiceFetcher对象代码处。

new CachedServiceFetcher<AudioManager>() {
    @Override
    public AudioManager createService(ContextImpl ctx) {
        return new AudioManager(ctx);
}}

这里是直接返回了新创建的AudioManager对象。

至此,上面

AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

就类似等价于

AudioManager audioManager =  new AudioManager(ctx);

参考文章

 历史上的今天

  1. 2023: Android加载动画常用做法简介(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

食指:相信未来

当蜘蛛网无情地查封了我的炉台当灰烬的余烟叹息着贫困的悲哀我依然固执地铺平失望的灰烬用美丽的雪花写下:相信未来 当我的紫葡萄化为深秋的露水当我的鲜花依偎在别人的情怀我依然固执地用凝霜的枯藤在凄凉的大地上写下:相信未来 我要用手指那涌向天边的排浪我要用手掌那托...

Android系统切换语言后,Activity中的文本没有改变

前言切换语言后,项目中的APP中的文本没有根据系统的语言改变而改变。这个是个小问题,但还是记录一下,方便自己查阅。正文隐藏内容!付费阅读后才能查看!¥1 ¥3多个隐藏块只需支付一次付费阅读参考文章《[摘]切换多国语言导致Fragment被回收,出现切换错乱》

汪曾祺:手把肉

蒙古人从小吃惯羊肉,几天吃不上羊肉就会想得慌。蒙古族舞蹈家斯琴高娃(蒙古族女的叫斯琴高娃的很多,跟那仁花一样的普遍)到北京来,带着她的女儿。她的女儿对北京的饭菜吃不惯。我们请她在晋阳饭庄吃饭,这小姑娘对红烧海参、脆皮鱼等等统统不感兴趣。我问她想吃什么,“羊肉!”我把服务员叫来,问他们这儿有没有羊肉,...

bootchart 的配置和使用

前言这里记录一下bootchart 的配置和使用,方便自己查阅。正文安装必要工具在设备端使能bootchart,抓取数据在服务器上解析bootchart数据,绘制成图分析bootchart.png安装必要工具略,由于公司编译代码的服务器是可以使用bootchart 命令,这里就...

[摘]android6.0运行时动态申请权限

从Android6.0以后,Android是不会主动获取需要权限,改为了需要提示用户手动获取,系统应用除外。1. 运行时获得权限:从androi 6.0开始,不再是安装应用时用户确定获得全部的权限.而是在使用软件过程中需要该权限时,弹出对话框让用户选择权限.不仅如此,用户选择权限后还可以关闭。...

Android 修改ListView快速滚动条的bar

前言最近需要使用修改ListView快速滚动条的bar,ListView是可以默认支持的,但就是太丑了,需要定制一下。下面就记录一下自己使用的方法。好记性不如烂笔头正文本文并非原创,感谢网友分享。隐藏内容!付费阅读后才能查看!¥2 ¥3多个隐藏块只需支付一次付费阅读