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 网络数据统计,例如流量管理会用到
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应用程序安装过程源代码分析