在代码中,经常需要调用系统服务,以下面代码片段为例:
private Set<Map.Entry<String, AutomaticZenRule>> getZenModeRules() {
Map<String, AutomaticZenRule> ruleMap
= NotificationManager.from(mContext).getAutomaticZenRules();
return ruleMap.entrySet();
}
图1
每次看的人是一脸懵逼,下面仅就这个问题进行探究,来看看源代码,定位到NotificationManager.java:
/** {@hide} */
public static NotificationManager from(Context context) {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
这里是调用了context的方法,而Context
的实现一般都在ContextImpl
中,事实也是如此,先查看context的getSystemService实现:
public abstract @Nullable Object getSystemService(@ServiceName @NonNull String name);
确实是抽象方法,只能去ContextImpl去找:
@Override
public Object getSystemService(String name) {
return SystemServiceRegistry.getSystemService(this, name);
}
继续调用了SystemServiceRegistry方法,SystemServiceRegistry是一个管理系统服务的类,这点我们后面再说,来看看其实现:
/**
* Gets a system service from a given context.
*/
public static Object getSystemService(ContextImpl ctx, String name) {
ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
return fetcher != null ? fetcher.getService(ctx) : null;
}
先获取ServiceFetcher,再尝试从ServiceFetcher中取服务,其中第二个参数是最开始传下来的,实际上就是Context.NOTIFICATION_SERVICE:
/**
* Use with {@link #getSystemService} to retrieve a
* {@link android.app.NotificationManager} for informing the user of
* background events.
*
* @see #getSystemService
* @see android.app.NotificationManager
*/
public static final String NOTIFICATION_SERVICE = "notification";
系统服务跟ServiceFetcher有啥关系呢,不妨先放在一边,顺着我们的NOTIFICATION_SERVICE字段,找到如下代码:
registerService(Context.NOTIFICATION_SERVICE, NotificationManager.class,
new CachedServiceFetcher<NotificationManager>() {
@Override
public NotificationManager createService(ContextImpl ctx) {
final Context outerContext = ctx.getOuterContext();
return new NotificationManager(
new ContextThemeWrapper(outerContext,
Resources.selectSystemTheme(0,
outerContext.getApplicationInfo().targetSdkVersion,
com.android.internal.R.style.Theme_Dialog,
com.android.internal.R.style.Theme_Holo_Dialog,
com.android.internal.R.style.Theme_DeviceDefault_Dialog,
com.android.internal.R.style.Theme_DeviceDefault_Light_Dialog)),
ctx.mMainThread.getHandler());
}});
这其实是服务注册的代码,传递了三个参数,第一个是服务的名字,第二个应该是服务对应的对象,第三个似乎跟ServiceFetcher有关,现在来看看ServiceFetcher的代码:
/**
* Base interface for classes that fetch services.
* These objects must only be created during static initialization.
*/
public static abstract interface ServiceFetcher<T> {
T getService(ContextImpl ctx);
}
是一个接口,CachedServiceFetcher是其具体的实现,实现了getService()方法:
/**
* Override this class when the system service constructor needs a
* ContextImpl and should be cached and retained by that context.
*/
public 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) {
try {
service = createService(ctx);
cache[mCacheIndex] = service;
} catch (ServiceNotFoundException e) {
onServiceNotFound(e);
}
}
return (T)service;
}
}
里面再调用createService()方法,注意上面的代码,service从先会从缓冲数组中取,不存在才会调用createService(),这实际上保证了服务的单例特性,进一步来看看registerService()方法:
/**
* Statically registers a system service with the context.
* This method must be called during static initialization only.
*/
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);
}
就是将serviceClass和serviceName放入SYSTEM_SERVICE_NAMES这个hashMap中,然后将serviceName和serviceFetcher放入SYSTEM_SERVICE_FETCHERS这个hashMap中,实际上就是回调到registerService中的createService(),并且在其中new出了NotificationManager对象并返回,ServiceFetcher可以看作是Service的生产工厂,createService()决定生产什么样的服务,至此可以的出结论最上图的NotificationManager.from(mContext)最终返回的是NotificationManager.java自己。
综上,NotificationManager.from(mContext)避免了用多个Context实例化XXmanager,由于registerService运行在static代码块中,避免了多次创建和销毁服务的情况,加载一次服务后服务不会销毁,加快了速度。
接下来还有一点让我很疑惑,NotificationManager走了一圈调用了自己,这有什么意义呢,难道不应该是调用远程服务来实现功能吗?在我的认知中,系统服务是运行在系统进程中,在我们的app进程中,调用NotificationManagerService这种服务至少要有aidl接口和跨进程操作吧,前面似乎很顺利,怕是遗漏了什么东西,直到看到了getAutomaticZenRules()函数的实现,也就是图1中需要调用的真正操作,来看看其实现:
public Map<String, AutomaticZenRule> getAutomaticZenRules() {
INotificationManager service = getService(); 1
try {
List<ZenModeConfig.ZenRule> rules = service.getZenRules();
Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
for (ZenModeConfig.ZenRule rule : rules) {
ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
rule.creationTime));
}
return ruleMap;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
看到1我豁然开朗,其最终还是需要去调用远程服务了,来看getService()实现:
/** @hide */
static public INotificationManager getService()
{
if (sService != null) {
return sService;
}
IBinder b = ServiceManager.getService("notification");
sService = INotificationManager.Stub.asInterface(b);
return sService;
}
看来NotificationManagerService.java应该继承了.stub接口,来看:
public class NotificationManagerService extends SystemService {
static final String TAG = "NotificationService";
static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
static final int MAX_PACKAGE_NOTIFICATIONS = 50;
static final float DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE = 5f;
......
}
excuse me,说好的继承接口呢,并没有,怕是我对远程调用的流程有什么误解,并不是,.stub已经成为了其内部类:
private final IBinder mService = new INotificationManager.Stub() {
// Toasts
// ============================================================================
@Override
public void enqueueToast(String pkg, ITransientNotification callback, int duration)
{
if (DBG) {
Slog.i(TAG, "enqueueToast pkg=" + pkg + " callback=" + callback
+ " duration=" + duration);
}
if (pkg == null || callback == null) {
Slog.e(TAG, "Not doing toast. pkg=" + pkg + " callback=" + callback);
return ;
}
final boolean isSystemToast = isCallerSystemOrPhone() || ("android".equals(pkg));
final boolean isPackageSuspended =
isPackageSuspendedForUser(pkg, Binder.getCallingUid());
......
}
}
里面确实实现了getAutomaticZenRules()方法,到这也就明白了,对调用者来讲,NotificationManager.from(mContext)是返回一个NotificationManager实例,但是这个实例并不负责具体的实现,需要具体实现时,内部还是封装了调用NotificationManagerService的过程,而后者其实也并不负责真正的实现,还是使用了代理的思想,交给内部类来真正实现INotificationManager接口方法,这就是一个完整的调用系统服务的过程!