ThinkSSL🔒 一键申购 5分钟快速签发 30天无理由退款 购买更放心 广告
那么IStatusBarService的真身如何呢?它的实现者是StatusBarManagerService。由于状态栏导航栏与它的关系十分密切,因此需要对其有所了解。 与WindowManagerService、InputManagerService等系统服务一样,StatusBarManagerService在ServerThread中创建。参考如下代码: **SystemServer.java-->ServerThread.run()** ``` public void run() { try { /* 创建一个StatusBarManagerService的实例,并注册到ServiceManager中使其成为 一个系统服务 */ statusBar = new StatusBarManagerService(context, wm); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch(Throwable e) {......} } 再看其构造函数: [StatusBarManagerService.java-->StatusBarManagerService.StatusBarManagerService()] public StatusBarManagerService(Context context,WindowManagerService windowManager) { mContext= context; mWindowManager = windowManager; // 监听实体键盘的状态变化 mWindowManager.setOnHardKeyboardStatusChangeListener(this); // 初始化状态栏的系统状态区的状态图标列表。关于系统状态区的工作原理将在7.2.3节介绍 finalResources res = context.getResources(); mIcons.defineSlots(res.getStringArray( com.android.internal.R.array.config_statusBarIcons)); } ``` 这基本上是系统服务中最简单的构造函数了,在这里并没有发现能够揭示StatusBarManagerService的工作原理的线索(由此也可以预见StatusBarManagerService的实现十分简单)。 接下来参考StatusBarManagerService.registerStatusBar()的实现。这个方法由SystemUI中的BaseStatusBar调用,用于建立其与StatusBarManagerService的通信连接,并取回保存在其中的信息副本。 **StatusBarManagerService.java-->StatusBarManagerService.registerStatusBar()** ``` public void registerStatusBar(IStatusBar bar,StatusBarIconList iconList, List<IBinder> notificationKeys,List<StatusBarNotification> notifications, intswitches[], List<IBinder> binders) { /* 首先是权限检查。状态栏与导航栏是Android系统中一个十分重要的组件,因此必须避免其他应用 调用此方法对状态栏与导航栏进行偷梁换柱。因此要求方法的调用者必须具有一个签名级的权限 android.permission.STATUS_BAR_SERVICE*/ enforceStatusBarService(); /* **① 将bar参数保存到mBar成员中。**bar的类型是IStatusBar,它即是BaseStatusBar中的 CommandQueue的Bp端。从此之后,StatusBarManagerService将通过mBar与BaseStatusBar 进行通信。因此可以理解mBar就是SystemUI中的状态栏与导航栏 */ mBar =bar; // **② 接下来依次为调用者返回信息副本** // 系统状态区的图标列表 synchronized (mIcons) { iconList.copyFrom(mIcons); } // 通知区的通知信息 synchronized (mNotifications) { for(Map.Entry<IBinder,StatusBarNotification> e: mNotifications.entrySet()) { notificationKeys.add(e.getKey()); notifications.add(e.getValue()); } } //switches中的杂项 synchronized (mLock) { switches[0] = gatherDisableActionsLocked(mCurrentUserId); ...... } ...... } ``` 可见StatusBarManagerService.registerStatusBar()的实现也十分简单。主要是保存BaseStatusBar中的CommandQueue的Bp端到mBar成员之中,然后再把信息副本填充到参数里去。尽管简单,但是从其实现中可以预料到StatusBarManagerService的工作方式:当它接受到操作状态栏与导航栏的请求时,首先将请求信息保存到副本之中,然后再将这一请求通过mBar发送给BaseStatusBar。以设置系统状态区图标这一操作为例,参考如下代码: **StatusBarManagerService.java-->StatusBarManagerService.setIcon()** ``` public void setIcon(String slot, StringiconPackage, int iconId, int iconLevel, String contentDescription) { /* 首先一样是权限检查,与registerStatusBar()不同,这次要求的是一个系统级别的权限 android.permission.STATUS_BAR。因为设置系统状态区图标的操作不允许普通应用程序进行。 其他的操作诸如添加一条通知则不需要此权限 */ enforceStatusBar(); synchronized (mIcons) { intindex = mIcons.getSlotIndex(slot); ...... StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.OWNER,iconId, iconLevel, 0, contentDescription); // **① 将图标信息保存在副本之中** mIcons.setIcon(index, icon); // **② 将设置请求发送给BaseStatusBar** if(mBar != null) { try { mBar.setIcon(index, icon); } catch (RemoteException ex) {......} } } } ``` 纵观StatusBarManagerService中的其他方法,会发现它们与setIcon()方法的实现十分类似。从而可以得知StatusBarManagerService的作用与工作原理如下: - 它是SystemUI中的状态栏与导航栏在system\_server中的代理。所有对状态栏或导航来有需求的对象都可以通过获取StatusBarManagerService的实例或Bp端达到其目的。只不过使用者必须拥有能够完成操作的相应权限。 - 它保存了状态栏/导航栏所需的信息副本,用于在SystemUI意外退出之后的恢复。