赞
踩
SystemUI属于系统级的apk,位置在frameworks\base\packages\SystemUI
,主要功能有:
SystemServer启动后,会在Main Thread启动ActivityManagerService,当ActivityManagerService systemReady后,会去启动SystemUIService。
SystemServer路径:frameworks/base/services/java/com/android/server/SystemServer.java
- mActivityManagerService.systemReady(new Runnable() {
- @Override
- public void run() {
- Slog.i(TAG, "Making services ready");
- ......
- Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
- try {
- startSystemUi(context);
- } catch (Throwable e) {
- reportWtf("starting System UI", e);
- }
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
- ......
- }
- });
在这个方法里启动一个SystemUIService服务
- static final void startSystemUi(Context context) {
- Intent intent = new Intent();
- intent.setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService"));
- intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
- //Slog.d(TAG, "Starting service: " + intent);
- context.startServiceAsUser(intent, UserHandle.SYSTEM);
- }
通过startServiceAsUser,SystemUIService就启动了,即SystemUI进程开机启动。
- public class SystemUIService extends Service {
-
- @Override
- public void onCreate() {
- super.onCreate();
- ((SystemUIApplication) getApplication()).startServicesIfNeeded();
- }
- ......
在SystemUIService的onCreate方法中会调用SystemUIApplication的startServicesIfNeeded方法,这个方法会调用 startServicesIfNeeded(SERVICES)方法启动一系列服务(并不是真正的service,都继承自SystemUI)。
- public class SystemUIApplication extends Application {
- ......
-
- /**
- * The classes of the stuff to start.
- */
- private final Class<?>[] SERVICES = new Class[] {
- com.android.systemui.tuner.TunerService.class,
- com.android.systemui.keyguard.KeyguardViewMediator.class,
- com.android.systemui.recents.Recents.class,
- com.android.systemui.volume.VolumeUI.class,
- Divider.class,
- com.android.systemui.statusbar.SystemBars.class,
- com.android.systemui.usb.StorageNotification.class,
- com.android.systemui.power.PowerUI.class,
- com.android.systemui.media.RingtonePlayer.class,
- com.android.systemui.keyboard.KeyboardUI.class,
- com.android.systemui.tv.pip.PipUI.class,
- com.android.systemui.shortcut.ShortcutKeyDispatcher.class,
- com.android.systemui.VendorServices.class
- };
-
- ......
-
- public void startServicesIfNeeded() {
- startServicesIfNeeded(SERVICES);
- }
- }
所有SERVICES统一继承了SystemUI类:
- public abstract class SystemUI {
- ......
-
- public abstract void start();
-
- protected void onConfigurationChanged(Configuration newConfig) {
- }
-
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- }
-
- protected void onBootCompleted() {
- }
-
- ......
- }
startServicesIfNeeded方法会遍历SERVICES 这个数组,依次调用service的start方法启动服务。
- private void startServicesIfNeeded(Class<?>[] services) {
- ......
-
- final int N = services.length;
- for (int i=0; i<N; i++) {
- Class<?> cl = services[i];
- if (DEBUG) Log.d(TAG, "loading: " + cl);
- try {
- Object newService = SystemUIFactory.getInstance().createInstance(cl);
- mServices[i] = (SystemUI) ((newService == null) ? cl.newInstance() : newService);
- } catch (IllegalAccessException ex) {
- throw new RuntimeException(ex);
- } catch (InstantiationException ex) {
- throw new RuntimeException(ex);
- }
-
- mServices[i].mContext = this;
- mServices[i].mComponents = mComponents;
- if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
- mServices[i].start();
-
- if (mBootCompleted) {
- mServices[i].onBootCompleted();
- }
- }
- ......
- }
状态栏(SystemBars)service是SystemUI中最重要的service,代码量最多,最复杂的,界面结构也复杂。根据前面的内容可知,启动SystemBars是通过调用start()方法,如下图:
- public void start() {
- if (DEBUG) Log.d(TAG, "start");
- mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
- mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
- mServiceMonitor.start(); // will call onNoService if no remote service is found
- }
这里实质是回调到到SystemBars的onNoService()方法,最后是调用SystemBars的createStatusBarFromConfig()方法:
- private void createStatusBarFromConfig() {
- ......
- String clsName = mContext.getString(R.string.config_statusBarComponent);
- ......
- try {
- cls = mContext.getClassLoader().loadClass(clsName);
- } catch (Throwable t) {
- throw andLog("Error loading status bar component: " + clsName, t);
- }
- try {
- mStatusBar = (BaseStatusBar) cls.newInstance();
- } catch (Throwable t) {
- throw andLog("Error creating status bar component: " + clsName, t);
- }
- ......
- mStatusBar.start();
- ......
- }
上图可以看到,从string资源文件里面读取class name,通过java的映射机制实例化对象,然后调用start()方法启动,class name的值如下图:
- <!-- Component to be used as the status bar service. Must implement the IStatusBar
- interface. This name is in the ComponentName flattened format (package/class) -->
- <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
该配置文件在SystemUI/res/values/config.xml
中。所以实质是PhoneStatusBar调用了start()方法。
SystemBars模块的初始化过程主要涉及的类有:
SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
PhoneStatusBar的父类是BaseStatusBar继承于SystemUI,SystemBars调用PhoneStatusBar中的start()方法,类关系图如下:
PhoneStatusBar的start()
- public void start() {
- ......
- super.start(); // calls createAndAddWindows()
-
- ......
- addNavigationBar();
-
- ......
- }
如上图,调用父类中的start()方法,即BaseStatsuBar中的start()方法。然后调用addNavigationBar()方法实例化导航条。状态栏的布局层次结构如下图:
继续看BaseStatsuBar中的方法。
- public void start() {
- ......
-
- mBarService = IStatusBarService.Stub.asInterface(
- ServiceManager.getService(Context.STATUS_BAR_SERVICE));
-
- ......
-
- // Connect in to the status bar manager service
- mCommandQueue = new CommandQueue(this);
-
- int[] switches = new int[9];
- ArrayList<IBinder> binders = new ArrayList<IBinder>();
- ArrayList<String> iconSlots = new ArrayList<>();
- ArrayList<StatusBarIcon> icons = new ArrayList<>();
- Rect fullscreenStackBounds = new Rect();
- Rect dockedStackBounds = new Rect();
- try {
- mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders,
- fullscreenStackBounds, dockedStackBounds);
- } catch (RemoteException ex) {
- // If the system process isn't there we're doomed anyway.
- }
-
- createAndAddWindows();
-
- ......
-
- // Set up the initial icon state
- int N = iconSlots.size();
- int viewIndex = 0;
- for (int i=0; i < N; i++) {
- setIcon(iconSlots.get(i), icons.get(i));
- }
-
- // Set up the initial notification state.
- try {
- mNotificationListener.registerAsSystemService(mContext,
- new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),
- UserHandle.USER_ALL);
- } catch (RemoteException e) {
- Log.e(TAG, "Unable to register notification listener", e);
- }
-
- ......
- }
如上面BaseStatsuBar中的start()方法,实例化一些对象,此处的对象都是“空值”,然后通过IStatusBarService的实例mBarService对象注册到StatusBarManagerService。
mCommandQueue是CommandQueue的实例,在StatusBarManagerService的远程回调,实现StatusBarManagerService和SystemUI的通信。
然后调用createAndAddWindows()方法,该方法初始化status bar,notification,quick settings等的View控件。
在这里,还需要注意NotificationListenerService的实例mNotificationListener的registerAsSystemService()方法,该方法主要实现StatusBarManagerService和SystemUI的notification的控制通道,也就是说,StatusBarManagerService收到notification变化时,通过此通道通知SystemUI显示notification的变化。
一个APP需要显示notification首先需要实例化一个NotificationManager的对象,然后调用NotificationManager的方法notify()方法把创建好的Notification对象作为参数传进去。
- public void notify(int id, Notification notification){
- notify(null, id, notification);
- }
- public void notify(String tag, int id, Notification notification){
- notifyAsUser(tag, id, notification, new UserHandle(UserHandle.myUserId()));
- }
- public void notifyAsUser(String tag, int id, Notification notification, UserHandle user){
- ......
- INotificationManager service = getService();
- ......
- try {
- service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
- copy, idOut, user.getIdentifier());
- ......
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
上图中可以看到一个service的对象调用了enqueueNotificationWithTag()方法,该方法实质是远程调用NotificationManagerService中的enqueueNotificationWithTag()方法,该方法又直接调用enqueueNotificationInternal(),该方法如下:
- void enqueueNotificationInternal(final String pkg, final String opPkg, final int callingUid,
- final int callingPid, final String tag, final int id, final Notification notification,
- int[] idOut, int incomingUserId) {
- ......
- final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, callingUid, callingPid, 0, notification,
- user);
-
- ......
-
- final NotificationRecord r = new NotificationRecord(getContext(), n);
- mHandler.post(new EnqueueNotificationRunnable(userId, r));
-
- ......
- }
这里会把NotificationManager传递过来的Notification对象进行很多处理,比如变换成NotificationRecord,实质就是把Notification缓存下来。在上图的这个过程,还有一些其它的处理逻辑,在这里就不详细说明。最后把这个NotificationRecord传递给EnqueueNotificationRunnable线程来处理:
- private class EnqueueNotificationRunnable implements Runnable {
- private final NotificationRecord r;
- private final int userId;
-
- EnqueueNotificationRunnable(int userId, NotificationRecord r) {
- this.userId = userId;
- this.r = r;
- };
-
- @Override
- public void run() {
-
- synchronized (mNotificationList) {
- final StatusBarNotification n = r.sbn;
- ......
-
- if (notification.getSmallIcon() != null) {
- StatusBarNotification oldSbn = (old != null) ? old.sbn : null;
- mListeners.notifyPostedLocked(n, oldSbn);
- } else {
- ......
- }
-
- buzzBeepBlinkLocked(r);
- }
- }
- }
代码的末尾调用了buzzBeepBlinkLocked()方法,该方法主要处理Notification的声音和震动的逻辑。mListeners调用了notifyPostedLocked()方法,此方法最终会执行到如下图的代码:
- private void notifyPosted(final ManagedServiceInfo info,
- final StatusBarNotification sbn, NotificationRankingUpdate rankingUpdate) {
- final INotificationListener listener = (INotificationListener)info.service;
- StatusBarNotificationHolder sbnHolder = new StatusBarNotificationHolder(sbn);
- try {
- listener.onNotificationPosted(sbnHolder, rankingUpdate);
- } catch (RemoteException ex) {
- Log.e(TAG, "unable to notify listener (posted): " + listener, ex);
- }
- }
info.service返回一个INotificationListener的实例对象,该对象在上文中的mNotificationListener.registerAsSystemService()方法进行设置,所以listener.onNotificationPosted()方法实质是远程回调SystemUI中的方法:
- private final NotificationListenerService mNotificationListener =
- new NotificationListenerService() {
- ......
-
- @Override
- public void onNotificationPosted(final StatusBarNotification sbn,
- final RankingMap rankingMap) {
- ......
- if (sbn != null) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- ......
-
- if (isUpdate) {
- updateNotification(sbn, rankingMap);
- } else {
- addNotification(sbn, rankingMap, null /* oldEntry */);
- }
- }
- });
- }
- }
- }
代码运行又回到了BaseStatusBar.java类中,从APP调用NotificationManager的notify()方法到BaseStatusBar的addNotification()或updateNotification()方法,经历了一个复杂的过程。就不再往下详情说明Notification到达SystemUI的处理过程了,之后有机会我们继续分析。
锁屏(Keyguard)service在SystemUI是一个比较特殊的模块,特殊在于SystemUI启动的service只是一个信息传递者,也就是KeyguardViewMediator,并没有做锁屏或解屏的实质操作。在这里,涉及到三个比较关键的类是:
SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
KeyguardViewMediator和KeyguardService在源码中位于SystemUI中,而KeyguardUpdateMonitor则位于KeyGuard中。在KeyguardViewMediator的初始化中主要做了三件事,如图:
- public void start() {
- synchronized (this) {
- setupLocked();
- }
- putComponent(KeyguardViewMediator.class, this);
- }
- private void setupLocked() {
- ......
-
- mUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
-
- ......
-
- mStatusBarKeyguardViewManager =
- SystemUIFactory.getInstance().createStatusBarKeyguardViewManager(mContext,
- mViewMediatorCallback, mLockPatternUtils);
- final ContentResolver cr = mContext.getContentResolver();
-
- mDeviceInteractive = mPM.isInteractive();
-
- ......
-
- if (soundPath != null) {
- mLockSoundId = mLockSounds.load(soundPath, 1);
- }
- if (soundPath == null || mLockSoundId == 0) {
- Log.w(TAG, "failed to load lock sound from " + soundPath);
- }
- soundPath = Settings.Global.getString(cr, Settings.Global.UNLOCK_SOUND);
- if (soundPath != null) {
- mUnlockSoundId = mLockSounds.load(soundPath, 1);
- }
- if (soundPath == null || mUnlockSoundId == 0) {
- Log.w(TAG, "failed to load unlock sound from " + soundPath);
- }
- soundPath = Settings.Global.getString(cr, Settings.Global.TRUSTED_SOUND);
- if (soundPath != null) {
- mTrustedSoundId = mLockSounds.load(soundPath, 1);
- }
- if (soundPath == null || mTrustedSoundId == 0) {
- Log.w(TAG, "failed to load trusted sound from " + soundPath);
- }
-
- ......
- }
实例化KeyguardUpdateMonitor的实例mUpdateMonitor,KeyguardUpdateMonitor负责更新已经锁屏界面上的内容(如时间)。当然,KeyguardUpdateMonitor只是一个信息传递者,实际去刷新界面的是StatusBar模块。Keyguard模块通知StatusBar刷新解密是通过KeyguardUpdateMonitorCallback这个类进行远程回调,该类的实例在StatusBar模块启动时通过KeyguardService获取到IKeyguardService的远端实例,通过IKeyguardService远程调用IKeyguardService的addStateMonitorCallback()方法实例化KeyguardUpdateMonitorCallback对象,SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
- private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
-
- @Override // Binder interface
- public void addStateMonitorCallback(IKeyguardStateCallback callback) {
- checkPermission();
- mKeyguardViewMediator.addStateMonitorCallback(callback);
- }
-
- ......
-
- @Override // Binder interface
- public void onScreenTurnedOn() {
- Trace.beginSection("KeyguardService.mBinder#onScreenTurningOn");
- checkPermission();
- mKeyguardViewMediator.onScreenTurnedOn();
- Trace.endSection();
- }
-
- ......
- };
SystemUI启动的Keyguard模块并没有真正的去操作锁屏界面,而是作为一个信息传递者把信息传递给StatusBar模块。
KeyguardService在KeyguardServiceDelegate中绑定调用。frameworks/base/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
:
- public void bindService(Context context) {
- Intent intent = new Intent();
- final Resources resources = context.getApplicationContext().getResources();
-
- final ComponentName keyguardComponent = ComponentName.unflattenFromString(
- resources.getString(com.android.internal.R.string.config_keyguardComponent));
- intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
- intent.setComponent(keyguardComponent);
-
- boolean isBox = isBox();
-
- if (isBox || !context.bindServiceAsUser(intent, mKeyguardConnection,
- Context.BIND_AUTO_CREATE, mScrimHandler, UserHandle.SYSTEM)) {
- Log.v(TAG, "*** Keyguard: can't bind to " + keyguardComponent);
- mKeyguardState.showing = false;
- mKeyguardState.showingAndNotOccluded = false;
- mKeyguardState.secure = false;
- synchronized (mKeyguardState) {
- // TODO: Fix synchronisation model in this class. The other state in this class
- // is at least self-healing but a race condition here can lead to the scrim being
- // stuck on keyguard-less devices.
- mKeyguardState.deviceHasKeyguard = false;
- hideScrim();
- }
- } else {
- if (DEBUG) Log.v(TAG, "*** Keyguard started");
- }
- }
-
- private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- if (DEBUG) Log.v(TAG, "*** Keyguard connected (yay!)");
- mKeyguardService = new KeyguardServiceWrapper(mContext,
- IKeyguardService.Stub.asInterface(service), mShowingStateChangedCallback);
- if (mKeyguardState.systemIsReady) {
- // If the system is ready, it means keyguard crashed and restarted.
- mKeyguardService.onSystemReady();
- if (mKeyguardState.currentUser != UserHandle.USER_NULL) {
- // There has been a user switch earlier
- mKeyguardService.setCurrentUser(mKeyguardState.currentUser);
- }
- // This is used to hide the scrim once keyguard displays.
- if (mKeyguardState.interactiveState == INTERACTIVE_STATE_AWAKE) {
- mKeyguardService.onStartedWakingUp();
- }
- if (mKeyguardState.screenState == SCREEN_STATE_ON
- || mKeyguardState.screenState == SCREEN_STATE_TURNING_ON) {
- mKeyguardService.onScreenTurningOn(
- new KeyguardShowDelegate(mDrawnListenerWhenConnect));
- }
- if (mKeyguardState.screenState == SCREEN_STATE_ON) {
- mKeyguardService.onScreenTurnedOn();
- }
- mDrawnListenerWhenConnect = null;
- }
- if (mKeyguardState.bootCompleted) {
- mKeyguardService.onBootCompleted();
- }
- if (mKeyguardState.occluded) {
- mKeyguardService.setOccluded(mKeyguardState.occluded, false /* animate */);
- }
- }
-
- @Override
- public void onServiceDisconnected(ComponentName name) {
- if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
- mKeyguardService = null;
- }
-
- };
com.android.internal.R.string.config_keyguardComponent
的默认配置值:
- <!-- Keyguard component -->
- <string name="config_keyguardComponent" translatable="false">com.android.systemui/com.android.systemui.keyguard.KeyguardService</string>
KeyguardViewMediator启动的流程图如下:
先大概看一遍流程,这个apk比较复杂,之后还会分析。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。