1. 什么是System UI
? ? ? ? SystemUI是Android系統(tǒng)級(jí)應(yīng)用,負(fù)責(zé)反饋系統(tǒng)及應(yīng)用狀態(tài)并與用戶保持大量的交互。業(yè)務(wù)主要涉及的組成部分包括狀態(tài)欄(Status Bar),通知欄(Notification Panel),鎖屏(Keyguard),控制中心(Quick Setting),音量調(diào)節(jié)(VolumeUI), 近期任務(wù)(Recents)等等。
圖例如下所示:
2. 源碼位置
package name: ? ?com.android.systemui
SystemUI源碼目錄位于: framework/base/packages/SystemUI
Application位于: ? ? ? ?frameworks\base\packages\SystemUI\SystemUIApplication
Service位于: ? ? ? ? ? ?frameworks\base\services\java\com\android\server\
3. systemUI 啟動(dòng)流程
SystemServer.run()-> startOtherServices()-> startSystemUi()
SystemServer由ZygoteInit進(jìn)程創(chuàng)建并啟動(dòng)
frameworks/base/services/java/com/android/server/SystemServer.java
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
......
// Start services.
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t); //在這里會(huì)啟動(dòng)startSystemUi()
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd(); // StartServices
}
......
}
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
......
try {
startSystemUi(context, windowManagerF);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
......
}
private static void startSystemUi(Context context, WindowManagerService windowManager) {
PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
Intent intent = new Intent();
intent.setComponent(pm.getSystemUiServiceComponent()); //這里
intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.SYSTEM);
windowManager.onSystemUiStarted();
}
注意看這一段?
intent.setComponent(pm.getSystemUiServiceComponent());
pm是PackageManagerInternal實(shí)例,它的getSystemUiServiceComponent()方法是一個(gè)抽象方法
frameworks/base/services/core/java/android/content/pm/PackageManagerInternal.java
/**
* @return The SystemUI service component name.
*/
public abstract ComponentName getSystemUiServiceComponent();
PackageManagerService實(shí)現(xiàn)了該方法,如下:
frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@Override
public ComponentName getSystemUiServiceComponent() {
return ComponentName.unflattenFromString(mContext.getResources().getString(
com.android.internal.R.string.config_systemUIServiceComponent));
}
?com.android.internal.R.string.config_systemUIServiceComponent的值是
frameworks/base/core/res/res/values/config.xml
>com.android.systemui/com.android.systemui.SystemUIService
?unflattenFromString返回的是ComponentName(“com.android.systemui”, “com.android.systemui.SystemUIService”);
unflattenFromString?具體方法如下,很簡(jiǎn)單,感興趣的可以看看,不感興趣的直接跳過就好,這個(gè)方法不是重點(diǎn)。
/**
* Recover a ComponentName from a String that was previously created with
* {@link #flattenToString()}. It splits the string at the first '/',
* taking the part before as the package name and the part after as the
* class name. As a special convenience (to use, for example, when
* parsing component names on the command line), if the '/' is immediately
* followed by a '.' then the final class name will be the concatenation
* of the package name with the string following the '/'. Thus
* "com.foo/.Blah" becomes package="com.foo" class="com.foo.Blah".
*
* @param str The String that was returned by flattenToString().
* @return Returns a new ComponentName containing the package and class
* names that were encoded in str
*
* @see #flattenToString()
*/
public static @Nullable ComponentName unflattenFromString(@NonNull String str) {
int sep = str.indexOf('/');
if (sep < 0 || (sep+1) >= str.length()) {
return null;
}
String pkg = str.substring(0, sep);
String cls = str.substring(sep+1);
if (cls.length() > 0 && cls.charAt(0) == '.') {
cls = pkg + cls;
}
return new ComponentName(pkg, cls);
}
以上代碼功能為通過Intent啟動(dòng)了SystemUIService。
于是走到SystemUIService的onCreate()方法
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
public void onCreate() {
super.onCreate();
// Start all of SystemUI
((SystemUIApplication) getApplication()).startServicesIfNeeded();
......
}
public void startServicesIfNeeded() {
String[] names = SystemUIFactory.getInstance().getSystemUIServiceComponents(getResources());
startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
}
通過工廠模式獲得SystemUI組件列表
frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
public String[] getSystemUIServiceComponents(Resources resources) {
return resources.getStringArray(R.array.config_systemUIServiceComponents);
}
?列表如下:
frameworks/base/packages/SystemUI/res/values/config.xml
?這個(gè)列表是要傳到上面的String[] names里的,作為參數(shù),下一步執(zhí)行startServicesIfNeeded(/* metricsPrefix= */ "StartServices", names);
方法如下:
大致內(nèi)容就是通過反射獲得上面列表的類的構(gòu)造函數(shù),然后通過構(gòu)造函數(shù)創(chuàng)建上面那些類的實(shí)例,然后調(diào)用這些類的start方法,啟動(dòng)這些systemuI組件。
private void startServicesIfNeeded(String metricsPrefix, String[] services) {
if (mServicesStarted) {
return;
}
mServices = new SystemUI[services.length];
if (!mBootCompleteCache.isBootComplete()) {
// check to see if maybe it was already completed long before we began
// see ActivityManagerService.finishBooting()
if ("1".equals(SystemProperties.get("sys.boot_completed"))) {
mBootCompleteCache.setBootComplete();
if (DEBUG) {
Log.v(TAG, "BOOT_COMPLETED was already sent");
}
}
}
final DumpManager dumpManager = mRootComponent.createDumpManager();
Log.v(TAG, "Starting SystemUI services for user " +
Process.myUserHandle().getIdentifier() + ".");
TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
Trace.TRACE_TAG_APP);
log.traceBegin(metricsPrefix);
final int N = services.length;
for (int i = 0; i < N; i++) {
String clsName = services[i]; //獲取類名
if (DEBUG) Log.d(TAG, "loading: " + clsName);
log.traceBegin(metricsPrefix + clsName);
long ti = System.currentTimeMillis();
try {
SystemUI obj = mComponentHelper.resolveSystemUI(clsName);
if (obj == null) {
Constructor constructor = Class.forName(clsName).getConstructor(Context.class); //獲取構(gòu)造函數(shù)
obj = (SystemUI) constructor.newInstance(this); //通過構(gòu)造函數(shù)獲取實(shí)例
}
mServices[i] = obj; //把實(shí)例放入到mServices數(shù)組中
} catch (ClassNotFoundException
| NoSuchMethodException
| IllegalAccessException
| InstantiationException
| InvocationTargetException ex) {
throw new RuntimeException(ex);
}
if (DEBUG) Log.d(TAG, "running: " + mServices[i]);
mServices[i].start(); //執(zhí)行start方法
log.traceEnd();
// Warn if initialization of component takes too long
ti = System.currentTimeMillis() - ti;
if (ti > 1000) {
Log.w(TAG, "Initialization of " + clsName + " took " + ti + " ms");
}
if (mBootCompleteCache.isBootComplete()) {
mServices[i].onBootCompleted();
}
dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
}
mRootComponent.getInitController().executePostInitTasks();
log.traceEnd();
mServicesStarted = true;
}
SystemUI的啟動(dòng)就是這樣。剩下的就是啟動(dòng)具體組件了,例如com.android.systemui.statusbar.phone.StatusBar。
StatusBar也就是狀態(tài)欄,想看狀態(tài)欄怎么啟動(dòng)的可以跟到它的start方法,這篇就先到這里。
?
?
?
?
?
文章鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。
轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。