ServiceManager.getService和Context.getSystemService

Context.getSystemService流程

拿获取TelephonyManager实例举例:

            TelephonyManager tm =
                    (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);

其中mContext是Context的一个实例

frameworks/base/core/java/android/content/Context.java

    public final <T> T getSystemService(Class<T> serviceClass) {
        // Because subclasses may override getSystemService(String) we cannot
        // perform a lookup by class alone.  We must first map the class to its
        // service name then invoke the string-based method.
        String serviceName = getSystemServiceName(serviceClass);
        return serviceName != null ? (T)getSystemService(serviceName) : null;
    }

先用getSystemServiceName获取服务名字,然后getSystemService返回结果,

frameworks/base/core/java/android/app/ContextImpl.java

 public String getSystemServiceName(Class<?> serviceClass) {
        return SystemServiceRegistry.getSystemServiceName(serviceClass);
    }

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

   public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();

SYSTEM_SERVICE_NAMES是HashMap,key是类,值是名字,初始化在registerService方法

    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }

registerService方法在static静态调用块中使用

 static {
    ...
            registerService(Context.TELEPHONY_SERVICE, TelephonyManager.class,
                new CachedServiceFetcher<TelephonyManager>() {
            @Override
            public TelephonyManager createService(ContextImpl ctx) {
                return new TelephonyManager(ctx.getOuterContext());
            }});
    ...
}

getSystemServiceName相关流程分析完毕,接下来是getSystemService流程:

   public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }

代码又回到SystemServiceRegistry.java中

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

这里的SYSTEM_SERVICE_FETCHERS同样是个HashMap,TelephonyManager.class对应的值其实就是刚才静态代码块中初始化代码中的:

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

CachedServiceFetcher定义如下:

static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;
 
        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }
 
        @Override
        @SuppressWarnings("unchecked")
        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) {
                    service = createService(ctx);
                    cache[mCacheIndex] = service;
                }
                return (T)service;
            }
        }
 
        public abstract T createService(ContextImpl ctx);

mCacheIndex就是系统服务的索引,每增加一个服务值就加1 ;mServiceCache是一个数组,依靠数组索引就可以获取服务。从代码可见service是单例的,只有在为null的时候才会创建,后续从数组获取即可。createService的实现在代码SystemServiceRegistry的static静态调用块中,前面已贴出,就是new了一个TelephonyManager的实例。由于service数组的引用最终是一个静态的数组,所以一个进程中的SystemService如TelephonyManager只有一个实例。
流程到这里还有个小问题,就是TelephonyManager传递进去的context会一直有引用,那么岂不是第一个获取TelephonyManager的实例的地方会有内存泄漏。例如传递进去一个Activity,那么Activity岂不是会泄漏?其实Android有处理的,答案在TelephonyManager的构造函数中:
 

 public TelephonyManager(Context context) {
        Context appContext = context.getApplicationContext();
        if (appContext != null) {
            mContext = appContext;
        } else {
            mContext = context;
        }
        ...
}

引用指向的是ApplicationContext,是没有泄漏这个问题的。

ServiceManager.getService

例如TelephonyManager中的getITelephony方法

   private ITelephony getITelephony() {
        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
    }

这个是跨进程binder相关,网上早有多个大神分析过binder机制,例如罗升阳的 Android进程间通信(IPC)机制Binder简要介绍和学习计划,ServiceManager的addService和getService有详细的分析。

Context中其它的SystemService

Context中的注释:

  /**
     * Return the handle to a system-level service by class.
     * <p>
     * Currently available classes are:
     * {@link android.view.WindowManager}, {@link android.view.LayoutInflater},
     * {@link android.app.ActivityManager}, {@link android.os.PowerManager},
     * {@link android.app.AlarmManager}, {@link android.app.NotificationManager},
     * {@link android.app.KeyguardManager}, {@link android.location.LocationManager},
     * {@link android.app.SearchManager}, {@link android.os.Vibrator},
     * {@link android.net.ConnectivityManager},
     * {@link android.net.wifi.WifiManager},
     * {@link android.media.AudioManager}, {@link android.media.MediaRouter},
     * {@link android.telephony.TelephonyManager}, {@link android.telephony.SubscriptionManager},
     * {@link android.view.inputmethod.InputMethodManager},
     * {@link android.app.UiModeManager}, {@link android.app.DownloadManager},
     * {@link android.os.BatteryManager}, {@link android.app.job.JobScheduler},
     * {@link android.app.usage.NetworkStatsManager}.
     * </p>     
     */

列举了SystemService形式使用的多种xxManager,除了有TelephonyManager,还有:
管理整个Android窗口UI的WindowerManager,它在android view机制中使用的比较多,app层可以使用它显示个悬浮窗什么的,例如360卫士和腾讯管家在来电时显示的覆盖在窗口最上层的悬浮窗;
管理控件布局的LayoutInflater,app用它来加载布局;
管理Activity生命周期的ActivityManager,系统使用,app层一般不用;
电源管理PowerManager,能休眠或者启动系统,申请WakeLock的方法和相关常量也在这个服务中
AlarmManager,系统定时提醒,多少时间后唤醒系统并发送alarm通知,例如闹钟使用
NotificationManager,状态栏通知相关,这个很常用
KeyguardManager,锁屏相关,例如可以获取当前是否锁屏,并有解锁方法
LocationManager,位置相关
SearchManager,Android搜索相关
SensorManager,传感器相关,如获取重力加速度传感器
StorageManager,存储相关,例如获取sd卡目录
Vibrator,振动相关
ConnectivityManager,数据连接相关
WifiManager,WiFi相关
AudioManager,音频相关,例如获取当前音量,当前音频模式,调整音量
MediaRouter,音频流切换,例如音乐是手机喇叭播放还是外接蓝牙音箱播放。
SubscriptionManager, sim卡相关,能获取当前插入的sim卡信息,其实根本机制是管理TelephonyProvider中的Siminfo表
CarrierConfigManager,通信设置相关,如控制通话记录数据库是否记录紧急通话
InputMethodManager,输入法相关,例如可以关闭当前弹出的输入法UI
UiModeManager,UI模式管理,其实Android除了最通常的UI外还提供了车载和桌面模式,模式切换时UI要有变化,不过遗憾的是android手机目前实现这个功能的很少(本人没有见过)
DownloadManager,下载相关,downloadProvider常量定义,下载请求,下载网络设置(如只能在wifi下下载)等
BatteryManager,电池相关
JobScheduler,执行某些特定条件下的任务,例如连接到电源后,连接到wifi等。把job提交到framework,然后framework会回调,回调代码是跑在提交job的进程中
NetworkStatsManager 网络数据统计,例如流量管理会用到
两种Service的不同
1.个人认为主要是两者层次不同
ServiceManager是binder机制相关的,比较底层;而Context中的SystemService属于上层,它是一个框架,简化了上层app开发。不用该框架,熟悉代码的程序员也可以直接使用ServiceManager调用相关服务。SystemService这套小框架的的目的在Android源码注释中很清楚了:

 

   * </p><p>
     * Note: System services obtained via this API may be closely associated with
     * the Context in which they are obtained from.  In general, do not share the
     * service objects between various different contexts (Activities, Applications,
     * Services, Providers, etc.)
     * </p>

避免了用多个Context实例化XXmanager, 通过SystemService每个进程的每个服务最多只有一个实例(没有用到的服务不会分配内存),节省内存;避免了多次创建和销毁服务的情况,加载一次服务后服务不会销毁,加快了速度。使用Context的SystemService不用考虑context传入后可能的内存泄漏,也不必顾忌多个SystemService实例消耗的内存。
2.SystemService使用ServiceManager;SystemService相当于客户端,ServiceManager相当于服务端;SystemService运行在context所在的进程,ServiceManager获取的service基本都是运行在system进程(phone服务是个例外,是运行在phone进程)。
ServiceManager是binder ipc相关,SystemService并没有直接提供服务实现,绝大多数都是使用了ServiceManager获取服务端,再调用服务端的方法。而名字叫做SystemService是因为binder的服务端基本都是跑在system进程的。见/frameworks/base/services/java/com/android/server/SystemServer,java,这个文件中添加了大多数的系统服务,都是运行在system进程中的。SystemServer的流程分析,不少Android系统启动流程的文章中都会有介绍,如 Android应用程序安装过程源代码分析
 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值