简要说明:
该分析基于android 8.1.0
StatusBar的启动流程
- systemservice ->main -> run -> startotherservice ->startsystemui -> startServiceAsUser()
// 启动systemService run方法
public static void main(String[] args) {
new SystemServer().run();
}
private void run ( ) {
....
// 启动服务
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();
startCoreServices();
startOtherServices();
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
}
private void startOtherService{
...
traceBeginAndSlog("StartSystemUI");
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
traceEnd();
...
}
static final void startSystemUi(Context context, WindowManagerService windowManager) {
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);
windowManager.onSystemUiStarted();
}
- 通过 startServiceAsUser 启动了SystemUIService
- SystemUIService -> onCreate -> ((SystemUIApplication) getApplication()).startServicesIfNeeded()
public class SystemUIService extends Service {
@Override
public void onCreate() {
super.onCreate();
((SystemUIApplication) getApplication()).startServicesIfNeeded();
// For debugging RescueParty
if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {
throw new RuntimeException();
}
}
...
}
- 通过startServicesIfNeeded 启动SystemBars
private final Class<?>[] SERVICES = new Class[] {
Dependency.class,
NotificationChannels.class,
CommandQueue.CommandQueueStart.class,
KeyguardViewMediator.class,
Recents.class,
VolumeUI.class,
Divider.class,
SystemBars.class,
StorageNotification.class,
PowerUI.class,
RingtonePlayer.class,
KeyboardUI.class,
PipUI.class,
ShortcutKeyDispatcher.class,
VendorServices.class,
GarbageMonitor.Service.class,
LatencyTester.class,
GlobalActionsComponent.class,
RoundedCorners.class,
};
private void startServicesIfNeeded(Class<?>[] services) {
if (mServicesStarted) {
return;
}
if (!mBootCompleted) {
// check to see if maybe it was already completed long before we began
// see ActivityManagerService.finishBooting()
if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
mBootCompleted = true;
if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");
}
}
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin("StartServices");
final int N = services.length;
for (int i = 0; i < N; i++) {
Class<?> cl = services[i];
if (DEBUG) Log.d(TAG, "loading: " + cl);
log.traceBegin("StartServices" + cl.getSimpleName());
long ti = System.currentTimeMillis();
try {
================================启动service=================================================
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();
log.traceEnd();
===========================end=====================================
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
Log.w(TAG, "Initialization of " + cl.getName() + " took " + ti + " ms");
}
if (mBootCompleted) {
mServices[i].onBootCompleted();
}
}
log.traceEnd();
Dependency.get(PluginManager.class).addPluginListener(
new PluginListener<OverlayPlugin>() {
private ArraySet<OverlayPlugin> mOverlays;
@Override
public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
StatusBar statusBar = getComponent(StatusBar.class);
if (statusBar != null) {
plugin.setup(statusBar.getStatusBarWindow(),
statusBar.getNavigationBarView());
}
// Lazy init.
if (mOverlays == null) mOverlays = new ArraySet<>();
if (plugin.holdStatusBarOpen()) {
mOverlays.add(plugin);
Dependency.get(StatusBarWindowManager.class).setStateListener(b ->
mOverlays.forEach(o -> o.setCollapseDesired(b)));
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}
@Override
public void onPluginDisconnected(OverlayPlugin plugin) {
mOverlays.remove(plugin);
Dependency.get(StatusBarWindowManager.class).setForcePluginOpen(
mOverlays.size() != 0);
}
}, OverlayPlugin.class, true /* Allow multiple plugins */);
mServicesStarted = true;
}
- systembars -> start() -> createStatusBarFromConfig -> mStatusBar = (SystemUI) cls.newInstance()... mStatusBar.start();
public class SystemBars extends SystemUI{
...
private void createStatusBarFromConfig() {
if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
final String clsName = mContext.getString(R.string.config_statusBarComponent);
if (clsName == null || clsName.length() == 0) {
throw andLog("No status bar component configured", null);
}
Class<?> cls = null;
try {
cls = mContext.getClassLoader().loadClass(clsName);
} catch (Throwable t) {
throw andLog("Error loading status bar component: " + clsName, t);
}
try {
mStatusBar = (SystemUI) cls.newInstance();
} catch (Throwable t) {
throw andLog("Error creating status bar component: " + clsName, t);
}
mStatusBar.mContext = mContext;
mStatusBar.mComponents = mComponents;
mStatusBar.start();
if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}
...
}
- StatusBar -> start() -> createAndAddWindows() - > addStatusBarWindow() ->makeStatusBarView()
protected void makeStatusBarView() {
final Context context = mContext;
updateDisplaySize(); // populates mDisplayMetrics
updateResources();
updateTheme();
inflateStatusBarWindow(context);
mStatusBarWindow.setService(this);
mStatusBarWindow.setOnTouchListener(getStatusBarWindowTouchListener());
// TODO: Deal with the ugliness that comes from having some of the statusbar broken out
// into fragments, but the rest here, it leaves some awkward lifecycle and whatnot.
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
R.id.notification_panel);
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
R.id.notification_stack_scroller);
mNotificationPanel.setStatusBar(this);
mNotificationPanel.setGroupManager(mGroupManager);
mAboveShelfObserver = new AboveShelfObserver(mStackScroller);
mAboveShelfObserver.setListener(mStatusBarWindow.findViewById(
R.id.notification_container_parent));
mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
mNotificationIconAreaController = SystemUIFactory.getInstance()
.createNotificationIconAreaController(context, this);
inflateShelf();
mNotificationIconAreaController.setupShelf(mNotificationShelf);
Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
FragmentHostManager.get(mStatusBarWindow)
.addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
CollapsedStatusBarFragment statusBarFragment =
(CollapsedStatusBarFragment) fragment;
statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);
mStatusBarView = (PhoneStatusBarView) fragment.getView();
mStatusBarView.setBar(this);
mStatusBarView.setPanel(mNotificationPanel);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setBouncerShowing(mBouncerShowing);
setAreThereNotifications();
checkBarModes();
}).getFragmentManager()
.beginTransaction()
.replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),
CollapsedStatusBarFragment.TAG)
.commit();
mIconController = Dependency.get(StatusBarIconController.class);
mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow, mGroupManager);
mHeadsUpManager.setBar(this);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanel);
mHeadsUpManager.addListener(mGroupManager);
mHeadsUpManager.addListener(mVisualStabilityManager);
mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
mNotificationData.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setHeadsUpManager(mHeadsUpManager);
mHeadsUpManager.setVisualStabilityManager(mVisualStabilityManager);
if (MULTIUSER_DEBUG) {
mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
R.id.header_debug_info);
mNotificationPanelDebugText.setVisibility(View.VISIBLE);
}
try {
boolean showNav = mWindowManagerService.hasNavigationBar();
if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
if (showNav) {
createNavigationBar();
}
} catch (RemoteException ex) {
// no window manager? good luck with that
}
// figure out which pixel-format to use for the status bar.
mPixelFormat = PixelFormat.OPAQUE;
mStackScroller.setLongPressListener(getNotificationLongClicker());
mStackScroller.setStatusBar(this);
mStackScroller.setGroupManager(mGroupManager);
mStackScroller.setHeadsUpManager(mHeadsUpManager);
mGroupManager.setOnGroupChangeListener(mStackScroller);
mVisualStabilityManager.setVisibilityLocationProvider(mStackScroller);
inflateEmptyShadeView();
inflateDismissView();
mExpandedContents = mStackScroller;
mBackdrop = (BackDropView) mStatusBarWindow.findViewById(R.id.backdrop);
mBackdropFront = (ImageView) mBackdrop.findViewById(R.id.backdrop_front);
mBackdropBack = (ImageView) mBackdrop.findViewById(R.id.backdrop_back);
if (ENABLE_LOCKSCREEN_WALLPAPER) {
mLockscreenWallpaper = new LockscreenWallpaper(mContext, this, mHandler);
}
mKeyguardIndicationController =
SystemUIFactory.getInstance().createKeyguardIndicationController(mContext,
(ViewGroup) mStatusBarWindow.findViewById(R.id.keyguard_indication_area),
mNotificationPanel.getLockIcon());
mNotificationPanel.setKeyguardIndicationController(mKeyguardIndicationController);
mAmbientIndicationContainer = mStatusBarWindow.findViewById(
R.id.ambient_indication_container);
// set the initial view visibility
setAreThereNotifications();
// TODO: Find better place for this callback.
mBatteryController.addCallback(new BatteryStateChangeCallback() {
@Override
public void onPowerSaveChanged(boolean isPowerSave) {
mHandler.post(mCheckBarModes);
if (mDozeServiceHost != null) {
mDozeServiceHost.firePowerSaveChanged(isPowerSave);
}
}
@Override
public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
// noop
}
});
mLightBarController = Dependency.get(LightBarController.class);
if (mNavigationBar != null) {
mNavigationBar.setLightBarController(mLightBarController);
}
ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
View headsUpScrim = mStatusBarWindow.findViewById(R.id.heads_up_scrim);
mScrimController = SystemUIFactory.getInstance().createScrimController(mLightBarController,
scrimBehind, scrimInFront, headsUpScrim, mLockscreenWallpaper,
scrimsVisible -> {
if (mStatusBarWindowManager != null) {
mStatusBarWindowManager.setScrimsVisible(scrimsVisible);
}
});
if (mScrimSrcModeEnabled) {
Runnable runnable = new Runnable() {
@Override
public void run() {
boolean asSrc = mBackdrop.getVisibility() != View.VISIBLE;
mScrimController.setDrawBehindAsSrc(asSrc);
mStackScroller.setDrawBackgroundAsSrc(asSrc);
}
};
mBackdrop.setOnVisibilityChangedRunnable(runnable);
runnable.run();
}
mHeadsUpManager.addListener(mScrimController);
mStackScroller.setScrimController(mScrimController);
mDozeScrimController = new DozeScrimController(mScrimController, context);
// Other icons
mVolumeComponent = getComponent(VolumeComponent.class);
mNotificationPanel.setUserSetupComplete(mUserSetup);
if (UserManager.get(mContext).isUserSwitcherEnabled()) {
createUserSwitcher();
}
// Set up the quick settings tile panel
View container = mStatusBarWindow.findViewById(R.id.qs_frame);
if (container != null) {
FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
Dependency.get(ExtensionController.class).newExtension(QS.class)
.withPlugin(QS.class)
.withFeature(
PackageManager.FEATURE_AUTOMOTIVE, () -> new CarQSFragment())
.withDefault(() -> new QSFragment())
.build());
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow,
mScrimController);
fragmentHostManager.addTagListener(QS.TAG, (tag, f) -> {
QS qs = (QS) f;
if (qs instanceof QSFragment) {
((QSFragment) qs).setHost(qsh);
mQSPanel = ((QSFragment) qs).getQsPanel();
mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
mKeyguardStatusBar.setQSPanel(mQSPanel);
}
});
}
mReportRejectedTouch = mStatusBarWindow.findViewById(R.id.report_rejected_touch);
if (mReportRejectedTouch != null) {
updateReportRejectedTouchVisibility();
mReportRejectedTouch.setOnClickListener(v -> {
Uri session = mFalsingManager.reportRejectedTouch();
if (session == null) { return; }
StringWriter message = new StringWriter();
message.write("Build info: ");
message.write(SystemProperties.get("ro.build.description"));
message.write("\nSerial number: ");
message.write(SystemProperties.get("ro.serialno"));
message.write("\n");
PrintWriter falsingPw = new PrintWriter(message);
FalsingLog.dump(falsingPw);
falsingPw.flush();
startActivityDismissingKeyguard(Intent.createChooser(new Intent(Intent.ACTION_SEND)
.setType("*/*")
.putExtra(Intent.EXTRA_SUBJECT, "Rejected touch report")
.putExtra(Intent.EXTRA_STREAM, session)
.putExtra(Intent.EXTRA_TEXT, message.toString()),
"Share rejected touch report")
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
true /* onlyProvisioned */, true /* dismissShade */);
});
}
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
if (!pm.isScreenOn()) {
mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
}
mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
"GestureWakeLock");
mVibrator = mContext.getSystemService(Vibrator.class);
int[] pattern = mContext.getResources().getIntArray(
R.array.config_cameraLaunchGestureVibePattern);
mCameraLaunchGestureVibePattern = new long[pattern.length];
for (int i = 0; i < pattern.length; i++) {
mCameraLaunchGestureVibePattern[i] = pattern[i];
}
// receive broadcasts
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
IntentFilter demoFilter = new IntentFilter();
if (DEBUG_MEDIA_FAKE_ARTWORK) {
demoFilter.addAction(ACTION_FAKE_ARTWORK);
}
demoFilter.addAction(ACTION_DEMO);
context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
android.Manifest.permission.DUMP, null);
// listen for USER_SETUP_COMPLETE setting (per-user)
mDeviceProvisionedController.addCallback(mUserSetupObserver);
mUserSetupObserver.onUserSetupChanged();
// disable profiling bars, since they overlap and clutter the output on app windows
ThreadedRenderer.overrideProperty("disableProfileBars", "true");
// Private API call to make the shadows look better for Recents
ThreadedRenderer.overrideProperty("ambientRatio", String.valueOf(1.5f));
}
makeStatusBarView()
6.1: 找到 mNotificationPanel
6.2: 找到 NotificationStackScrollLayout
6.3: 找到KeyguardStatusBarView
6.4: 创建NotificationIconAreaController
6.5: 找到KeyguardIndicationController
6.6: createNavigationBar();
....
Notification
- NotificationManager -> notify -> notifyAsUser() -> enqueueNotificationWithTag(说明调用者: INotificationManager)
aidl默认调用NotificationManagerService
- NotificationManagerService -> enqueueNotificationWithTag() -> enqueueNotificationInternal()
post(new EnqueueNotificationRunnable(userid, r)); 将Notification发送到EnqueueNotificationRunnable 处理
- EnqueueNotificationRunnable -> run() -> PostNotificationRunnable-> run
调用 NotificationManagerService.NotificationManager 的 notifyRemovedLocked
NotificationManagerService.NotificationManager -> notifyPosted() -> listener.onNotificationPosted(sbnHolder, rankingUpdate);
PopupDataProvider -> onNotificationPosted -> updateLauncherIconBadges -> updateNotificationHeader -> updateNotificationHeader -> mNotificationItemView.updateHeader(badgeInfo.getNotificationCount(), palette);
NotificationItemView -> updateHeader
NavigationBar
- StatusBar -> start() -> createAndWindows() ->addStatusBarWindow() -> makeStatusBarView() -> createNavigationBar()
protected void createNavigationBar() {
mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
mNavigationBar = (NavigationBarFragment) fragment;
if (mLightBarController != null) {
mNavigationBar.setLightBarController(mLightBarController);
}
mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
});
}
KeyGuard
- StatusBar -> start() -> startKeyguard() -> keyguardViewMediator.registerStatusBar
- KeyguradViewMediator -> registerStatusBar
- StatusBarKeyguardViewManager ->registerStatusBar -> SystemUIFactory.getInstance().createKeyguardBouncer
- SystemUIFactory -> createKeyguardBouncer
// mContainer (viewGroup) 其实是 StatusBarWindowView的对象
- KeyguardBouncer -> inflateView -> mContainer.addView(mRoot, mContainer.getChildCount())
KeyguardBouncer 部分核心源码:
public KeyguardBouncer(Context context, ViewMediatorCallback callback,
LockPatternUtils lockPatternUtils, ViewGroup container,
DismissCallbackRegistry dismissCallbackRegistry) {
mContext = context;
mCallback = callback;
mLockPatternUtils = lockPatternUtils;
mContainer = container;
KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
mFalsingManager = FalsingManager.getInstance(mContext);
mDismissCallbackRegistry = dismissCallbackRegistry;
mHandler = new Handler();
}
public void show(boolean resetSecuritySelection) {
final int keyguardUserId = KeyguardUpdateMonitor.getCurrentUser();
if (keyguardUserId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser()) {
// In split system user mode, we never unlock system user.
return;
}
mFalsingManager.onBouncerShown();
ensureView();
if (resetSecuritySelection) {
// showPrimarySecurityScreen() updates the current security method. This is needed in
// case we are already showing and the current security method changed.
mKeyguardView.showPrimarySecurityScreen();
}
if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
return;
}
final int activeUserId = ActivityManager.getCurrentUser();
final boolean isSystemUser =
UserManager.isSplitSystemUser() && activeUserId == UserHandle.USER_SYSTEM;
final boolean allowDismissKeyguard = !isSystemUser && activeUserId == keyguardUserId;
// If allowed, try to dismiss the Keyguard. If no security auth (password/pin/pattern) is
// set, this will dismiss the whole Keyguard. Otherwise, show the bouncer.
if (allowDismissKeyguard && mKeyguardView.dismiss(activeUserId)) {
return;
}
// This condition may indicate an error on Android, so log it.
if (!allowDismissKeyguard) {
Slog.w(TAG, "User can't dismiss keyguard: " + activeUserId + " != " + keyguardUserId);
}
mShowingSoon = true;
// Split up the work over multiple frames.
DejankUtils.postAfterTraversal(mShowRunnable);
}
protected void inflateView() {
removeView();
mHandler.removeCallbacks(mRemoveViewRunnable);
mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
mKeyguardView = mRoot.findViewById(R.id.keyguard_host_view);
mKeyguardView.setLockPatternUtils(mLockPatternUtils);
mKeyguardView.setViewMediatorCallback(mCallback);
mContainer.addView(mRoot, mContainer.getChildCount());
mStatusBarHeight = mRoot.getResources().getDimensionPixelOffset(
com.android.systemui.R.dimen.status_bar_height);
mRoot.setVisibility(View.INVISIBLE);
final WindowInsets rootInsets = mRoot.getRootWindowInsets();
if (rootInsets != null) {
mRoot.dispatchApplyWindowInsets(rootInsets);
}
}