context.getSystemService分析

本文详细解析了NotificationManager的实现原理,从源代码层面探讨了如何通过NotificationManager.from(mContext)调用系统服务,揭示了其背后的服务注册、缓存机制及远程调用过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在代码中,经常需要调用系统服务,以下面代码片段为例:

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接口方法,这就是一个完整的调用系统服务的过程!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值