編輯:關於Android編程
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system # zygote需要一個套接字
onrestart write /sys/android_power/request_state wake # zygote重啟的話,需要執行這個操作
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
*上述腳本表示要啟動一個進程,名稱為zygote, 可執行文件為/system/bin/app_process, --Xzygote /system/bin --zygote --start-system-server這些是傳給zygote的參數,其余部分的作用見注釋。
int main(int argc, char* const argv[])
{
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i
三、main函數主要就是創建了runtime實例,並且解析參數,然後調用runtime的start函數,接著我們分析AppRuntime的start函數
// 首先明確下傳進來的參數 className == "com.android.internal.os.ZygoteInit" options == "start-system-server"
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == 0) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1); //配置ANDROID_ROOT環境變量
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) { // 創建虛擬機
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
/* 調用com.android.internal.os.ZygoteInit的main函數,strArray是參數,數組裡面有兩個元素,
className == "com.android.internal.os.ZygoteInit" options == "start-system-server" */
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
四、start函數主要做了以下幾件事情:
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket(); // 1、創建一個套接字,用於監聽ams發過來的fork請求
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(); // 2、加載classes 和resources, 後面會詳細分析
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer(); //3、 創建system server進程,ams wms pms等常見service都在該進程裡面
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
if (ZYGOTE_FORK_MODE) {
runForkMode();
} else {
runSelectLoopMode(); // 4、進入循環監聽模式,監聽外來請求
}
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
五、com.android.internal.os.ZygoteInit的main函數主要做了四件事情:
public class ZygoteInit {
...
private static LocalServerSocket sServerSocket;
private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
private static void registerZygoteSocket() {
if(sServerSocket == NULL) {
int fileDesc;
String env = System.getenv(ANDROID_SOCKET_ENV); // 獲取環境變量
fileDesc = Integer.parseInt(env);
sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));
}
}
}
*這裡通過System.getenv()獲取環境變量ANDROID_SOCKET_ENV的值,通過這個文件描述符表示/dev/socket/zygote。那麼這個環境變量又是誰設置的呢?執行系統啟動腳本init.rc的init.c文件裡面有個service_start()函數就是用來分析zygote並創建和設置相應socket的。
void service_start(struct service *svc, const char* dynamic_args)
{
...
pid = fork();
if ( pid == 0)
{
struct socketinfo *si;
...
for (si = svc->sockets; si; si = si->next) {
int socket_type = (!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type, si->perm, si->uid, si->gid);
publish_socket(si->name, s);
}
}
...
}
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
char val[64];
strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) -1, name, sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
snprintf(val, sizeof(val), "%d", fd);
add_environment(key, val); // ANDROID_SOCKET_zygote = val
fcntl(fd, F_SETFD, 0);
}
*這裡每一個service命令都會使init進程調用fork函數創建一個新的進程來分析裡面的socket選項,然後調用create_socket()函數在/dev/socket目錄下創建一個設備文件,然後獲得一個文件描述符並通過publish_socket()寫入到環境變量中去。這樣就把zygote這個socket的文件描述符寫到ANDROID_SOCKET_zygote裡面去了,這裡創建socket文件描述符的create_socket()函數,最後通過調用execve(svc->args[0], (char**)arg_ptrs, (char**)ENV)去執行zygote的可執行程序,並將環境變量ENV參數傳遞過去了。所以ZygoteInit.registerZygoteSocket()函數就可以直接從環境變量中取出這個文件描述符來使用。如果其他進程需要打開這個/dev/socket/zygote 文件來和Zygote進程通信就需要通過文件名字連接LocalServerSocket。
private static boolean startSystemServer() {
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006...",
"--capabilities=13010432,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
int pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities));
if (pid == 0) { // 子進程
handleSystemServerProcess(parsedArgs);
}
return true; // 父進程直接返回true
}
*這裡Zygote進程通過調用Zygote.forkSystemServer()函數創建一個新的進程來啟動SystemServer組件。
public class ZygoteInit {
....
private static void handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
closeServerSocket(); // 子進程不需要zygote套接字,直接關閉
FileUtils.setUMask(FileUtils.S_IRWXG | FileUtils.S_IRWXO);
...
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
}
}
public class RuntimeInit {
...
public static final void zygoteInit(int targetSdkVersion, String[] argv) {
redirectLogStreams();
commonInit();
zygoteInitNative(); // 是一個native函數,主要完成Binder通信機制的初始化
applicationInit(targetSdkVersion, argv);
}
public static final native void zygoteInitNative();
private static void applicationInit(int targetSdkVersion, String[] argv) {
VMRuntime.getRuntime().setTargetHeapUtilizatoin(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
args = new Arguments(argv);
invokeStaticMain(args.startClass, args.startArgs);
}
// 這個 className = "com.android.server.SystemServer"
private static void invokeStaticMain(String className, String[] argv) {
Class cl;
cl = Class.forName(className);
Method m;
m = cl.getMethod("main", new Class[] {String[].class});
...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
}
*這個RuntimeInit.ZygoteInit()函數主要執行兩個操作:一是調用zygoteInitNative來執行一個Binder進程間通信機制的初始化工作;二是調用com.android.server.SystemServer類的main函數。
static JNINativeMethod gMethods[] = {
....
{ "zygoteInitNative", "()V", (void*) com_android_internal_os_RuntimeInit_zygoteInit },
....
};
static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit(); // 就是啟動Binder通信
}
virtual void onZygoteInit()
{
sp proc = ProcessState::self(); // 每個進程一份ProcessState對象,打開Binder驅動
if(proc->supportsProcess()){
proc->startThreadPool(); // 啟動一個線程用於Binder通信
}
}
*SystemServer.main :
public class SystemServer {
native public static void init1(Strig[] args);
public static void main(String[] args) {
....
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
System.loadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
*@frameworks/base/services/jni/com_android_server_SystemServer.cpp
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
system_init();
}
status_t system_init()
{
sp proc(ProcessState::self());
sp sm = defaultServiceManager();
...
AndroidRuntime* runtime = AndroidRuntime::getRuntime();
JNIEnv* env = rungime->getJNIEnv();
jclass clazz = env->FindClass("com/android/server/SystemServer");
jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");
env->CallStaticVoidMethod(clazz, methodId);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return NO_ERROR;
}
*這個SystemServer的main()函數首先會調用JNI方法init1,init1()會調用SystemServer的init2,在init2裡面創建一個ServerThread線程執行一些系統關鍵服務的啟動操作。
class ServerThread extends Thread {
...
public void run() {
Looper.prepare();
// Critical services ...
ServiceManager.addService(Context.POWER_SERVICE, new PoperManagerService());
ActivityManagerService.main();
PackageManagerService.main(context);
...
}
}
*到現在為止,zygote已經fork()子進程完成了SystemServer組件的初始化啟動操作,回到zygote.main()裡面調用runSelectLoopMode()進入一個循環再前面創建的socket接口上等待ActivityManagerService請求創建新的應用程序。
3、runSelectLoopMode
public class ZygoteInit {
....
private static void runSelectLoopMode() throws MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(NULL);
int loopCount = GC_LOOP_COUNT; // 10
while(true) {
fdArray = fds.toArray(fdArray);
index = selectReadble(fdArray); // 類似Linux下的select輪詢,native 函數
if(index < 0) {
...
} else if(index == 0) { // 表示有客戶端連接上
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else { // 客戶端發送了請求過來,交給ZygoteConnection的runOnce()函數完成
boolean done = peers.get(index).runOnce();
if(done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
private static ZygoteConnection acceptCommandPeer() {
...
return new ZygoteConnection(sServerSocket.accept());
}
}
*這裡while(true)循環裡面調用selectReadble(),這是一個native函數,類似select使用多路復用I/O模型。當返回0的時候表示有客戶端連接上,ZygoteConnection表示Zygote的一個客戶端,每當客戶端連接上的時候acceptCommandPeer()返回一個ZygoteConnection對象,ZygoteConnection裡面保存著accpet()返回的LocalSocket對象。然後將相應的文件描述符添加到fds裡面,下次再對其調用selelct輪詢。當返回值大於0的時候表示有客戶端發過來的數據請求,交給ZygoteConnection對象的runOnce()函數處理。
static jint com_android_internal_os_ZygoteInit_selectReadable (
JNIEnv *env, jobject clazz, jobjectArray fds)
{
if (fds == NULL) {
jniThrowNullPointerException(env, "fds == null");
return -1;
}
jsize length = env->GetArrayLength(fds);
fd_set fdset;
if (env->ExceptionOccurred() != NULL) {
return -1;
}
FD_ZERO(&fdset);
int nfds = 0;
for (jsize i = 0; i < length; i++) {
jobject fdObj = env->GetObjectArrayElement(fds, i);
if (env->ExceptionOccurred() != NULL) {
return -1;
}
if (fdObj == NULL) {
continue;
}
int fd = jniGetFDFromFileDescriptor(env, fdObj);
if (env->ExceptionOccurred() != NULL) {
return -1;
}
FD_SET(fd, &fdset);
if (fd >= nfds) {
nfds = fd + 1;
}
}
int err;
do {
err = select (nfds, &fdset, NULL, NULL, NULL);
} while (err < 0 && errno == EINTR);
if (err < 0) {
jniThrowIOException(env, errno);
return -1;
}
for (jsize i = 0; i < length; i++) {
jobject fdObj = env->GetObjectArrayElement(fds, i);
if (env->ExceptionOccurred() != NULL) {
return -1;
}
if (fdObj == NULL) {
continue;
}
int fd = jniGetFDFromFileDescriptor(env, fdObj);
if (env->ExceptionOccurred() != NULL) {
return -1;
}
if (FD_ISSET(fd, &fdset)) {
return (jint)i;
}
}
return -1;
}
總結:*應用進程和服務進程位於不同的進程中,他們之間是通過IPC進行數據傳遞的。
Android觸摸事件傳遞圖解
本博文講解流程TouchEvent相關事件簡介流程圖分解講解總結與歸納一.TouchEvent相關事件簡介 android TouchEvent相關事件有&nb
將替代ListView的RecyclerView 的使用詳解(一)
RecyclerView 是 android-support-v7-21 版本中新增的一個 Widgets, 還有一個 CardView 會在下次介紹使用。官方介紹 Re
Android ExpandableListView相關介紹
一、ExpandableListView介紹 一個垂直滾動的顯示兩個級別(Child,Group)列表項的視圖,列表項來自ExpandableListAdapter
Android WebView上實現JavaScript與Java交互
其實webview加載資源的速度並不慢,但是如果資源多了,當然就很慢。圖片、css 、js 、html這些資源每個大概需要10-200ms ,一般都是30ms就ok了。不