2011年11月21日星期一

Android process


[First written by Steve Guo, please keep the mark if forwarding.]

In this topic you will learn some information about Android process management. First let’s take a look at the launched processes during Android booting.
USER PID PPID VSIZE RSS WCHAN PC NAME
root 1 0 264 176 c00acc6c 0000c36c S /init
root 28 1 724 308 c0051354 afe0c4cc S /system/bin/sh
system 30 1 796 248 c026516c afe0b74c S /system/bin/servicemanager
root 31 1 1824 316 ffffffff afe0b50c S /system/bin/mountd
root 32 1 652 248 c02976e0 afe0c0bc S /system/bin/debuggerd
radio 33 1 5344 664 ffffffff afe0bdbc S /system/bin/rild
root 34 1 71028 18828 c00ad308 afe0b874 S zygote
media 37 1 16812 3456 ffffffff afe0b74c S /system/bin/mediaserver
root 39 1 788 288 c02f9ae4 afe0b50c S /system/bin/installd
system 86 34 187756 21836 ffffffff afe0b74c S system_server
radio 118 34 103476 13896 ffffffff afe0c824 S com.android.phone
app_4 124 34 117848 19248 ffffffff afe0c824 S android.process.acore
app_5 139 34 98672 11516 ffffffff afe0c824 S com.android.mms
app_3 151 34 92096 10976 ffffffff afe0c824 S com.android.alarmclock
app_6 161 34 94436 12616 ffffffff afe0c824 S com.android.calendar
app_9 173 34 93248 11728 ffffffff afe0c824 S android.process.media
app_15 182 34 91848 9764 ffffffff afe0c824 S com.android.voicedialer
app_16 190 34 94524 10812 ffffffff afe0c824 S android.process.im
They can be divided into three kinds.

Root Process

init is the first process after kernel booting. The major task it performs:
l Parser and execute init.rc and init.%hardware%.rc
l Automatically generate device node under /dev
l Start log and property service
l Monitor for device, property set and child process exit events

Native Application Process

According to init.rc, init will fork the following native application process.
console: star a shell.
servicemanager: start binder IPC service manager.
mountd: mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs.
debuggerd: start debug system.
rild: start radio interface layer daemon.
zygote: start Android Java VM Runtime and start system server. It’s the most important process.
mediaserver: start AudioFlinger, MediaPlayerService and CameraService.
installd: start install package daemon.

JAVA Application Process

Every JAVA application process is forked from zygote process. system_server is a special JAVA process, which is directly forked from zygote.. Other JAVA process is created from ActivityManagerService(run in system_server process) like this.
int pid = Process.start("android.app.ActivityThread",
mSimpleProcessManagement ? app.processName : null, uid, uid,
gids, ((app.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0), null);
While Process.java use UNIX domain socket to communicate with zygote. So the overall picture is shown as following.
clip_image002
System Server
It’s the first JAVA application launched by zygote. It starts the core Android services, e.g. ActivityManager, WindowManager, PackageManager etc. It’s the Android core engine.
Persistent Application
During booting, ActivityManagerService.systemReady will start all persistent applications.
List apps = ActivityThread.getPackageManager().
getPersistentApplications(PackageManager.GET_SHARED_LIBRARY_FILES);
if (apps != null) {
int N = apps.size();
int i;
for (i=0; i<N; i++) {
ApplicationInfo info
= (ApplicationInfo)apps.get(i);
if (info != null &&
!info.packageName.equals("android")) {
addAppLocked(info);
}
}
}
Currently only Phone application is registered as a persistent app in AndroidManifest.xml like this.
<application android:name="PhoneApp"
android:persistent="true"
android:label="@string/dialerIconLabel"
android:icon="@drawable/ic_launcher_phone">
So during booting, only phone application is automatically launched. It’s the “com.android.phone” process.
The First Activity
The first activity is launched by senting Intent.CATEGORY_HOME intent from ActivityManagerService.
Intent intent = new Intent(
mTopAction,
mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
ActivityInfo aInfo =
intent.resolveActivityInfo(mContext.getPackageManager(),
PackageManager.GET_SHARED_LIBRARY_FILES);
if (aInfo != null) {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
ProcessRecord app = getProcessRecordLocked(aInfo.processName,
aInfo.applicationInfo.uid);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivityLocked(null, intent, null, null, 0, aInfo,
null, null, 0, 0, 0, false);
}
}
It’s the “android.process.acore” process. (The process name is defined in AndroidManifest.xml)
Auto-launched Application After Booting
When activity idle is detected in ActivityManagerService, it will broadcast ACTION_BOOT_COMPLETED intent at the first time.
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
// Tell anyone interested that we are done booting!
synchronized (this) {
broadcastIntentLocked(null, null,
new Intent(Intent.ACTION_BOOT_COMPLETED, null),
null, null, 0, null, null,
android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
false, false, MY_PID, Process.SYSTEM_UID);
}
}
Currently, MMS, AlarmClock, Calendar, MediaProvider, VoiceDialer and IM have registered as a receiver for ACTION_BOOT_COMPLETED intent in their AndroidManifest.xml. So they will be automatically launched. (This explains the remained JAVA process.)
Email also registers as a receiver for ACTION_BOOT_COMPLETED intent in its AndroidManifest.xml, but it defines android:enable=”false”. So it won’t be launched.
<receiver android:name=".service.BootReceiver"
android:enabled="false"
>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_LOW" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.DEVICE_STORAGE_OK" />
</intent-filter>
</receiver>
DownloadProvider also registers as a receiver for ACTION_BOOT_COMPLETED intent in its AndroidManifest.xml, but it defines android:exported=”false”. So it won’t be launched.
<receiver android:name=".DownloadReceiver" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Behind the JAVA process
system_server is a special case. It calls ActivityThread.java’s systemMain static function, which creates an instance of ActivityThread. ActivityThread then creates an instance of ApplicationThread, Application and ApplicationContext.
Every other JAVA process works in a different way. It’s controlled by system_server while forked by zygote. When any JAVA process other than system_server is forked from zygote, it automatically calls ActivityThread.java’s main static function(See Process.java and the following code snippet).
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError (newStderr, "Error starting. ", ex);
}
The ActivityThread.java’s main function creates an instance of ActivityThread. ActivityThread then creates an instance of ApplicationThread. The ApplicationThread will work as an IBinder object to interact with ActivityManagerService in system_server. The new process does nothting at this time other than waiting IPC call from system_server. The Application and ApplicationContext object won’t be created at this time. Actually it’s deferred to when the process really works, eg. start an activity, receive intent or start a service.
For example, when start an activity, ActivityManagerService know which process the to-be-launched activity should run in, so it will RPC call ApplicationThread’s scheduleLaunchActivity to launch a new activity in that process. ApplicationThread then post a message to let ActivityThread know it needs to start an activity. ActivityThread then creates Application and ApplicationContext object. After that, it calls Instrumentation, then Instrumentation finally calls JAVA dalvik VM to really create an activity JAVA object.

Another version:

[First written by Steve Guo, please keep the mark if forwarding.]

init is the first process after kernel started. The corresponding source code lies in: device/system/init. It does the following tasks step by step:
1.       Initialize log system.
2.       Parse /init.rc and /init.%hardware%.rc.
3.       Execute early-init action in the two files parsed in step 2.
4.       Device specific initialize. For example, make all device node in /dev and download firmwares.
5.       Initialize property system. Actually the property system is working as a share memory. Logically it looks like a registry under Windows system.
6.       Execute init action in the two files parsed in step 2.
7.       Start property service.
8.       Execute early-boot and boot actions in the two files parsed in step 2.
9.       Execute property action in the two files parsed in step 2.
10.   Enter into an indefinite loop to wait for device/property set/child process exit events. For example, if an SD card is plugined, init will receive a device add event, so it can make node for the device. Most of the important process is forked in init, so if any of them crashed, init will receive a SIGCHLD then translate it into a child process exit event, so in the loop init can handle the process exit event and execute the commands defined in *.rc(it will run command onrestart).

The .rc file is a script file defined by Android. The default is device/system/rootdir/init.rc. We can take a loot at the file format(device/system/init/readme.txt is a good overall introduction of the script). Basically the script file contains actions and services.

Actions
——-
Actions are named sequences of commands. Actions have a trigger which is used to determine when the action should occur.  When an event occurs which matches an action’s trigger, that action is added to the tail of a to-be-executed queue (unless it is already on the queue).
Each action in the queue is dequeued in sequence and each command in that action is executed in sequence. Init handles other activities (device creation/destruction, property setting, process restarting) "between" the execution of the commands in activities.
Actions take the form of:
on <trigger>
   <command>
   <command>
   <command>

Services
——–
Services are programs which init launches and (optionally) restarts when they exit.  Services take the form of:
service <name> <pathname> [ <argument> ]*
   <option>
   <option>
   …

Options
——-
Options are modifiers to services.  They affect how and when init runs the service.

Triggers
——–
Triggers are strings which can be used to match certain kinds of events and used to cause an action to occur.

The builtin supported commands are defined in device/system/init/keywords.h. Commands are implementd in device/system/init/bultins.c.

The init program only executes five kinds of triggers: “early-init”, “init”, “early-boot”, “boot”, “property:*”. Take a look at the following line in default init.rc.
class_start default
This line is a command for the action corresponding to “boot” trigger. It will start all services whose class name equals to “default”. By default, if no class option is defined for a service, the service’s class name is “default”. So this line will start all the services in the order of position in the file by default. (BTW, you can start any service using start commands, if you like.) Any service is run as a forked process of init, take a look at the source code of service_start in device/system/init.c.

So according to the default init.rc, the following services will be executed step by step:
console: star a shell. The source is in device/system/bin/ash.
adbd: start adb daemon. The source is in device/tools/adbd. By default is disabled.
servicemanager: start binder system. The source is in device/commands/binder.
mountd: mount all fs defined in /system/etc/mountd.conf if started, receive commands through local socket to mount any fs. The source is in device/system/bin/mountd.
debuggerd: start debug system. The source is in device/system/bin/debuggerd.
rild: start radio interface layer daemon. The source is in device/commands/rind.
zygote: start Android Java Runtime and start system server. It’s the most important service. The source is in device/servers/app.
media: start AudioFlinger, MediaPlayerService and CameraService. The source is in device/commands/mediaserver.
bootsound: play the default boot sound /system/media/audio/ui/boot.mp3. The source is in device/commands/playmp3.
dbus: start dbus daemon, it’s only used by BlueZ. The source is in device/system/Bluetooth/dbus-daemon.
hcid: redirect hcid’s stdout and stderr to the Android logging system. The source is in device/system/bin/logwrapper. By default is disabled.
hfag: start Bluetooth handsfree audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.
hsag: start Bluetooth headset audio gateway, it’s only used by BlueZ. The source is in device/system/Bluetooth/bluez-utils. By default is disabled.
installd: start install package daemon. The source is in device/servers/installd.
flash_recovery: load /system/recovery.img. The source is in device/commands/recovery/mtdutils.

Zygote service does the following tasks step by step:
1.       Create JAVA VM.
2.       Register android native function for JAVA VM.
3.       Call the main function in the JAVA class named com.android.internal.os.ZygoteInit whose source is device/java/android/com/android/internal/os/ZygoteInit.java.
a)         Load ZygoteInit class
b)        Register zygote socket
c)        Load preload classes(the default file is device/java/android/preloaded-classes)
d)        Load preload resources
e)         Call Zygote::forkSystemServer (implemented in device/dalvik/vm/InternalNative.c) to fork a new process. In the new process, call the main function in the JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server.
                         i.              Load libandroid_servers.so
                       ii.              Call JNI native init1 function implemented in device/libs/android_servers/com_android_server_SystemServers. It only calls system_init implemented in device/servers/system/library/system_init.cpp.
l         If running on simulator, instantiate AudioFlinger, MediaPlayerService and CameraService here.
l         Call init2 function in JAVA class named com.android.server.SystemServer, whose source is in device/java/services/com/android/server. This function is very critical for Android because it start all of Android JAVA services.
l         If not running on simulator, call IPCThreadState::self()->joinThreadPool() to enter into service dispatcher.

SystemServer::init2 will start a new thread to start all JAVA services as follows:
Core Services:
1.       Starting Power Manager
2.       Creating Activity Manager
3.       Starting Telephony Registry
4.       Starting Package Manager
5.       Set Activity Manager Service as System Process
6.       Starting Context Manager
7.       Starting System Context Providers
8.       Starting Battery Service
9.       Starting Alarm Manager
10.   Starting Sensor Service
11.   Starting Window Manager
12.   Starting Bluetooth Service
13.   Starting Mount Service
Other services
1.       Starting Status Bar Service
2.       Starting Hardware Service
3.       Starting NetStat Service
4.       Starting Connectivity Service
5.       Starting Notification Manager
6.       Starting DeviceStorageMonitor Service
7.       Starting Location Manager
8.       Starting Search Service
9.       Starting Clipboard Service
10.   Starting Checkin Service
11.   Starting Wallpaper Service
12.   Starting Audio Service
13.   Starting HeadsetObserver
14.   Starting AdbSettingsObserver
Finally SystemServer::init2 will call ActivityManagerService.systemReady to launch the first activity by senting Intent.CATEGORY_HOME intent.

There is another way to start system server, which is through a program named system_server whose source is device/servers/system/system_main.cpp. It also calls system_init to start system services. So there is a question: why does Android have two methods to start system services? My guess is that directly start system_server may have synchronous problem with zygote because system_server will call JNI to start SystemServer::init2, while at that time zygote may not start JAVA VM yet. So Android uses another method. After zynote is initialized, fork a new process to start system services.

没有评论: