SystemServer#run()
private void run() {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
}
// If the system has "persist.sys.language" and friends set, replace them with
// "persist.sys.locale". Note that the default locale at this point is calculated
// using the "-Duser.locale" command line flag. That flag is usually populated by
// AndroidRuntime using the same set of system properties, but only the system_server
// and system apps are allowed to set them.
//
// NOTE: Most changes made here will need an equivalent change to
// core/jni/AndroidRuntime.cpp
if (!SystemProperties.get("persist.sys.language").isEmpty()) {
final String languageTag = Locale.getDefault().toLanguageTag();
SystemProperties.set("persist.sys.locale", languageTag);
SystemProperties.set("persist.sys.language", "");
SystemProperties.set("persist.sys.country", "");
SystemProperties.set("persist.sys.localevar", "");
}
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setActvityManagerService.LifecycleTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper();
// Initialize native services.
System.loadLibrary("android_servers");
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();//重点分析1
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services.
try {
startBootstrapServices();//重点分析2
startCoreServices();
startOtherServices();//重点分析3
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
SystemServer#createSystemContext()
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
}
ContextImpl#createSystemContext()
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread,
packageInfo, null, null, false, null, null, Display.INVALID_DISPLAY);
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetricsLocked());
return context;
}
为什么这个context是叫systemContext?因为在初始化ContextImpl时使用了一个LoadedAPK对象。
LoadedAPK用于保存一些和APK相关的信息(如资源文件和JNI库的位置等)。LoadedApk(ActivityThread)
mApplicationInfo.packageName = "android";
mPackageName = "android";
该packageName对应的是framework-res.apk,由于APK仅供system_server进程使用,所以称
该context为systemContextcreateSystemContext()中还创建了ActivityThread,这是代表了应
用进程的主线程,这说明system_server进程是一个特殊
的应用进程。
SystemServer#createSystemContext()总结
* 得到一个ActivityThread对象,它代表应用进程的主线程
* 得到一个Context对象,它指向的Application环境与framework-res.apk有关
* Android运行环境:在这个环境中,进程概念被模糊化,组件的运行及他们之间的交互均在该环
境中实现(或者说依赖该环境,即依赖Context和ActivityThread)
创建AMS对象:
systemServer#run() -> startBootstrapServices()
// Wait for installd to finish starting up so that it has a chance to
// create critical directories such as /data/user with the appropriate
// permissions. We need this to complete before we initialize other services.
Installer installer = mSystemServiceManager.startService(Installer.class);
// Activity manager runs the show.
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mActivityManagerService.setInstaller(installer);
//...
mActivityManagerService.setSystemProcess()
ActvityManagerService.Lifecycle
public Lifecycle(Context context) {
super(context);
mService = new ActivityManagerService(context);
}
ActivityManagerService#setSystemProcess()
public void setSystemProcess() {
try {
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));//打印内存信息
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
if (MONITOR_CPU_USAGE) {
ServiceManager.addService("cpuinfo", new CpuBinder(this));
}
ServiceManager.addService("permission", new PermissionController(this));
ServiceManager.addService("processinfo", new ProcessInfoService(this));
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);//查询对应PackageName的ApplicationInfo
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());//重点分析
synchronized (this) {//AMS对应用进程的纳入管理
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
} catch (PackageManager.NameNotFoundException e) {
throw new RuntimeException(
"Unable to find android system package", e);
}
}
* 向ServiceManagerService注册几个服务,注册了AMS,meminfo,gfxinfo等服务
* 向PackageManagerService查询package名为android的Application。PMKS与AMS同属一个进程
但二者仍然借助Context(可用于跨进程通信)。因PMKS和AMS处于同一个进程,此处完全可以直接
调用PKMS的函数。原因是Android希望system_server中的服务也通过Android运行环境来交互。
* 调用ActivityThread#installSystemApplicationInfo,用于将Context和ApplicationInfo绑定。
* 因为有些APK运行在system_server进程中,所以system_server作为一个特殊的应用进程,
也需要被AMS管理,而AMS中的进程管理结构是ProcessRecord。创建一个代表system_server
进程的ProcessRecord
SystemServer#startOtherServices()
mActivityManagerService.installSystemProviders();
这个Provider就是SettingsProviders.apk里的那个SettingsProvider。由于该apk的manifest中声明
的uid为android.uid.system,process name为system,所以可以确定SettingsProvider.apk是运行在
system_server进程中,和framework-res.apk在同一进程。因为ContentProvider是运行在定义它的
那个应用的进程中(如果contentProvider没有声明在单独线程的话),所以此时不用去创建进程再去
安装provider。关于更详细的ContentProvider的安装过程看《深入理解Android2》第七章,给个
ContentProvider从客户端调用getContentProvider到返回这个过程的流程图:
SystemServer#startOtherServices() -> ActivityManagerService#systemReady(final Runnable goingCallback)
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
mSystemServiceManager.startBootPhase(
SystemService.PHASE_ACTIVITY_MANAGER_READY);
try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
Slog.i(TAG, "WebViewFactory preparation");
WebViewFactory.prepareWebViewInSystemServer();
try {
startSystemUi(context);
} catch (Throwable e) {
reportWtf("starting System UI", e);
}
try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
}
try {
if (networkManagementF != null) networkManagementF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Managment Service ready", e);
}
try {
if (networkStatsF != null) networkStatsF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Stats Service ready", e);
}
try {
if (networkPolicyF != null) networkPolicyF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Policy Service ready", e);
}
try {
if (connectivityF != null) connectivityF.systemReady();
} catch (Throwable e) {
reportWtf("making Connectivity Service ready", e);
}
try {
if (audioServiceF != null) audioServiceF.systemReady();
} catch (Throwable e) {
reportWtf("Notifying AudioService running", e);
}
Watchdog.getInstance().start();
// It is now okay to let the various system services start their
// third party code...
mSystemServiceManager.startBootPhase(
SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
可将ActivityManagerService#systemReady()的工作分为三个阶段:
第一阶段:
发送PRE_BOOT_COMPLETED广播,该广播接收者的工作好像和系统升级有关
第二阶段:
* 杀死那些在AMS注册了的,还未启动完毕就先启动的应用进程。这些应用进程一定是APK
所在的java进程,因为只有应用进程才会向AMS注册,而一般的Native(例如mediaserver)进程是不会向AMS注册的。
* 从Settings数据库中获取配置信息。
第三阶段:
* 调用systemReady设置的回调对象goingCallback的run函数。
* 启动那些声明了persistent的APK(persistent应用在意外挂掉后,AMS会自动重启该APK)
* 启动桌面
startHomeActivityLocked(mCurrentUserId, "systemReady");
goingCallback的run函数
* 执行startSystemUi,在该函数内部启动SystemUIService,该Service和状态栏有关。
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);
}
* 调用一些服务的systemReady
AMS中的Service都启动完毕,Home也靓丽登场,整个系统准备完毕,。最后发送
ACTION_BOOT_COMPLETED广播
ActivityStackSupervisor#activityIdleInternalLocked(…) ->
ActivityManagerService#postfinishBooting() -> …-> ActivityManagerService#finishBooting()
ActivityManagerService#finishBooting()
Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
broadcastIntentLocked(null, null, intent, null,
new IIntentReceiver.Stub() {
@Override
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
synchronized (ActivityManagerService.this) {
requestPssAllProcsLocked(SystemClock.uptimeMillis(),
true, false);
}
}
},
0, null, null,
new String[] {android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
AppOpsManager.OP_NONE, null, true, false,
MY_PID, Process.SYSTEM_UID, userId);
由
AMS-启动Activity之二 这篇文章可知,activityIdleInternalLocked是在目标Activityresume后才调用的,
就是说ACTION_BOOT_COMPLETED广播是在Home Activity启动后才发出的。
最后是一些补充的知识点和总结:
* 一个进程可以运行多个Application,system_server进程就是一个典型例子。(运行了framework-res.apk和SettingsProvider.apk)
* AMS通过IApplicationThread与应用进程通信
* Binder系统支持客户端监听服务端的死亡消息。
* 从运行效率角度看,多个服务和系统核心Application放在同一个进程(system_server进程)是合理的,
因为很多Service都依赖Settings的数据库,把它们放在同一进程中,可以降低由于进程间通信带来的
效率损失。
*