2.1 SystemUI 启动
SystemUI是一个app,它所在的系统源码路径为:
androidSource/frameworks/base/packages/SystemUI
它的目录结构如下:
我们可以根据Android.mk配置信息可以看出这个模块最终编译成SystemUI.apk,生成的产物是在out/target/product/(productname)/system/priv-app/SystemUI.apk
由于安装包最后是放在了system/priv-app目录下,所以SystemUI.apk会开机便会被安装,安装好了,是不是就意味着开机就能看到状态栏与导航栏了呢,当然不是,这就需要被其他的服务拉起来,那下面就开始分析状态栏的启动过程。整个流程为:init->zygote->ZygoteInit->SystemServer->startSystemUi->SystemUIService->SystemBars->PhoneStatusBar
我们直接到SystemServer这步,上文有说明,前面几步可以参考上篇文章,这里不再赘述。
下面是函数跳转:
ActivityManagerService.self().systemReady(new Runnable() {
public void run() {
.......//此处省略n行
if (!headless) {
startSystemUi(contextF);
}
.......//此处省略n行
}
});
然后到startSystemUi函数:
static final void startSystemUi(Context context) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
//Slog.d(TAG, "Starting service: " + intent);
context.startServiceAsUser(intent, UserHandle.OWNER);
}
上边代码可以看到它启动了SystemUIService.java,代码位置:
./frameworks/base/packages/SystemUI/src/com/android/systemui/SystemUIService.java
可以看到这里启动了各个服务,如Recents,SystemBars,PowerUI等服务,这里我们只分析SystemBars的启动。
public void onCreate() {
//add begin
boolean isLowRam = SystemProperties.getBoolean("ro.config.low_ram", false);
if(isLowRam) {
SERVICES = new Class[] {
//com.android.systemui.recent.Recents.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.settings.SettingsUI.class,
};
}
mServices = new SystemUI[SERVICES.length];
//add end
HashMap<Class<?>, Object> components = new HashMap<Class<?>, Object>();
final int N = SERVICES.length;
for (int i=0; i<N; i++) {
Class<?> cl = SERVICES[i];
Log.d(TAG, "loading: " + cl);
try {
mServices[i] = (SystemUI)cl.newInstance();
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InstantiationException ex) {
throw new RuntimeException(ex);
}
mServices[i].mContext = this;
mServices[i].mComponents = components;
Log.d(TAG, "running: " + mServices[i]);
mServices[i].start();
}
}
我们可以看到服务最终是通过start方法启动的,那我们就走到SystemBars.java看他的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
}
public void start() {
// listen for setting changes
ContentResolver cr = mContext.getContentResolver();
cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);
// listen for package/component changes
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
mHandler.sendEmptyMessage(MSG_START_SERVICE);
}
private final Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch(msg.what) {
case MSG_START_SERVICE:
startService();
break;
case MSG_CONTINUE_START_SERVICE:
continueStartService();
break;
case MSG_STOP_SERVICE:
stopService();
break;
case MSG_PACKAGE_INTENT:
packageIntent((Intent)msg.obj);
break;
case MSG_CHECK_BOUND:
checkBound();
break;
case MSG_SERVICE_DISCONNECTED:
serviceDisconnected((ComponentName)msg.obj);
break;
}
}
};
private void startService() {
mServiceName = getComponentNameFromSetting();
if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
if (mServiceName == null) {
mBound = false;
mCallbacks.onNoService();
} else {
long delay = mCallbacks.onServiceStartAttempt();
mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
}
}
start函数最后调用到了onNoService函数
public void onNoService() {
if (DEBUG) Log.d(TAG, "onNoService");
createStatusBarFromConfig(); // fallback to using an in-process implementation
}
那我们走入里面实现中的createStatusBarFromConfig函数的实现:
private void createStatusBarFromConfig() {
if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
final String clsName = mContext.getString(R.string.config_statusBarComponent); //1
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 = (BaseStatusBar) 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());
}
注释1作用是通过配置文件,获取string字段,
由此可知最后是走到了PhoneStatusBar类的start函数,好的,已经快分析完了,再接着往下看其start的实现:
public void start() {
mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
.getDefaultDisplay();
updateDisplaySize();
super.start(); // 2
addNavigationBar(); //3
// Lastly, call to the icon policy to install/update all the icons.
mIconPolicy = new PhoneStatusBarPolicy(mContext);
mHeadsUpObserver.onChange(true); // set up
if (ENABLE_HEADS_UP) {
mContext.getContentResolver().registerContentObserver(
Settings.Global.getUriFor(SETTING_HEADS_UP), true,
mHeadsUpObserver);
}
}
注释2代码的作用就是开启状态栏,注释3代码开启导航栏。super.start();这段代码最后会调用到createAndAddWindow()函数,然后调用addStatusBarWindow函数:
private void addStatusBarWindow() {
// Put up the view
final int height = getStatusBarHeight();
// Now that the status bar window encompasses the sliding panel and its
// translucent backdrop, the entire thing is made TRANSLUCENT and is
// hardware-accelerated.
final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
height,
WindowManager.LayoutParams.TYPE_STATUS_BAR,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
PixelFormat.TRANSLUCENT);
lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
lp.gravity = getStatusBarGravity();
lp.setTitle("StatusBar");
lp.packageName = mContext.getPackageName();
makeStatusBarView();
mWindowManager.addView(mStatusBarWindow, lp);
}
上面的代码我们需要注意的makeStatusBarView这一段代码。makeStatusBarView里的代码比较多,其主要工作是实例化状态栏,通知栏等控件,并为之添加事件,如果不需要展示状态栏与导航栏,可以隐藏显示,这里通过两个方法实现了隐藏功能。首先是在makeStatusBarView函数中:
mStatusBarWindow.setBackground(null);
将状态栏里的背景设置为空,那么状态栏将会变成一个小黑条,这不大好看,那么就还需要一个操作,改配置文件的属性,代码路径为:
./frameworks/base/core/res/res/values/dimes.xml
修改的代码如下:
很简单,就是将状态栏和导航栏的高度变成0了,那当然也就看不到他们了,哈哈。到此,分析结束。
整个流程如下: