posts - 101,  comments - 29,  trackbacks - 0

                  Android應用程序框架層創建的應用程序進程具有兩個特點,一是進程的入口函數是ActivityThread.main,二是進程天然支持Binder進程間通信機制;這兩個特點都是在進程的初始化過程中實現的,本文將詳細分析Android應用程序進程創建過程中是如何實現這兩個特點的。

                  Android應用程序框架層創建的應用程序進程的入口函數是ActivityThread.main比較好理解,即進程創建完成之后,Android應用程序框架層就會在這個進程中將ActivityThread類加載進來,然后執行它的main函數,這個main函數就是進程執行消息循環的地方了。Android應用程序框架層創建的應用程序進程天然支持Binder進程間通信機制這個特點應該怎么樣理解呢?前面我們在學習Android系統的Binder進程間通信機制時說到,它具有四個組件,分別是驅動程序、守護進程、Client以及Server,其中Server組件在初始化時必須進入一個循環中不斷地與Binder驅動程序進行到交互,以便獲得Client組件發送的請求,具體可參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文,但是,當我們在Android應用程序中實現Server組件的時候,我們并沒有讓進程進入一個循環中去等待Client組件的請求,然而,當Client組件得到這個Server組件的遠程接口時,卻可以順利地和Server組件進行進程間通信,這就是因為Android應用程序進程在創建的時候就已經啟動了一個線程池來支持Server組件和Binder驅動程序之間的交互了,這樣,極大地方便了在Android應用程序中創建Server組件。

                  在Android應用程序框架層中,是由ActivityManagerService組件負責為Android應用程序創建新的進程的,它本來也是運行在一個獨立的進程之中,不過這個進程是在系統啟動的過程中創建的。ActivityManagerService組件一般會在什么情況下會為應用程序創建一個新的進程呢?當系統決定要在一個新的進程中啟動一個Activity或者Service時,它就會創建一個新的進程了,然后在這個新的進程中啟動這個Activity或者Service,具體可以參考Android系統在新進程中啟動自定義服務過程(startService)的原理分析Android應用程序啟動過程源代碼分析Android應用程序在新的進程中啟動新的Activity的方法和過程分析這三篇文章。

                  ActivityManagerService啟動新的進程是從其成員函數startProcessLocked開始的,在深入分析這個過程之前,我們先來看一下進程創建過程的序列圖,然后再詳細分析每一個步驟。


                 點擊查看大圖

                  Step 1. ActivityManagerService.startProcessLocked

                  這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityManagerService.java文件中:

          public final class ActivityManagerService extends ActivityManagerNative  
                  implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {  
            
              ......  
            
              private final void startProcessLocked(ProcessRecord app,  
                          String hostingType, String hostingNameStr) {  
            
                  ......  
            
                  try {  
                      int uid = app.info.uid;  
                      int[] gids = null;  
                      try {  
                          gids = mContext.getPackageManager().getPackageGids(  
                              app.info.packageName);  
                      } catch (PackageManager.NameNotFoundException e) {  
                          ......  
                      }  
                        
                      ......  
            
                      int debugFlags = 0;  
                        
                      ......  
                        
                      int pid = Process.start("android.app.ActivityThread",  
                          mSimpleProcessManagement ? app.processName : null, uid, uid,  
                          gids, debugFlags, null);  
                        
                      ......  
            
                  } catch (RuntimeException e) {  
                        
                      ......  
            
                  }  
              }  
            
              ......  
            
          }  
                  它調用了Process.start函數開始為應用程序創建新的進程,注意,它傳入一個第一個參數為"android.app.ActivityThread",這就是進程初始化時要加載的Java類了,把這個類加載到進程之后,就會把它里面的靜態成員函數main作為進程的入口點,后面我們會看到。

           

                  Step 2. Process.start 

                  這個函數定義在frameworks/base/core/java/android/os/Process.java文件中:

          public class Process {
          	......
          
          	public static final int start(final String processClass,
          		final String niceName,
          		int uid, int gid, int[] gids,
          		int debugFlags,
          		String[] zygoteArgs)
          	{
          		if (supportsProcesses()) {
          			try {
          				return startViaZygote(processClass, niceName, uid, gid, gids,
          					debugFlags, zygoteArgs);
          			} catch (ZygoteStartFailedEx ex) {
          				......
          			}
          		} else {
          			......
          
          			return 0;
          		}
          	}
          
          	......
          }
                 這里的supportsProcesses函數返回值為true,它是一個Native函數,實現在frameworks/base/core/jni/android_util_Process.cpp文件中:

           

          jboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
          {
              return ProcessState::self()->supportsProcesses();
          }

           

                 ProcessState::supportsProcesses函數定義在frameworks/base/libs/binder/ProcessState.cpp文件中:

          bool ProcessState::supportsProcesses() const
          {
              return mDriverFD >= 0;
          }
          
                 這里的mDriverFD是設備文件/dev/binder的打開描述符,如果成功打開了這個設備文件,那么它的值就會大于等于0,因此,它的返回值為true。

           

                 回到Process.start函數中,它調用startViaZygote函數進一步操作。

                 Step 3. Process.startViaZygote

                 這個函數定義在frameworks/base/core/java/android/os/Process.java文件中:

          public class Process {
          	......
          
          	private static int startViaZygote(final String processClass,
          			final String niceName,
          			final int uid, final int gid,
          			final int[] gids,
          			int debugFlags,
          			String[] extraArgs)
          			throws ZygoteStartFailedEx {
          		int pid;
          
          		synchronized(Process.class) {
          			ArrayList<String> argsForZygote = new ArrayList<String>();
          
          			// --runtime-init, --setuid=, --setgid=,
          			// and --setgroups= must go first
          			argsForZygote.add("--runtime-init");
          			argsForZygote.add("--setuid=" + uid);
          			argsForZygote.add("--setgid=" + gid);
          			if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
          				argsForZygote.add("--enable-safemode");
          			}
          			if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
          				argsForZygote.add("--enable-debugger");
          			}
          			if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
          				argsForZygote.add("--enable-checkjni");
          			}
          			if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
          				argsForZygote.add("--enable-assert");
          			}
          
          			//TODO optionally enable debuger
          			//argsForZygote.add("--enable-debugger");
          
          			// --setgroups is a comma-separated list
          			if (gids != null && gids.length > 0) {
          				StringBuilder sb = new StringBuilder();
          				sb.append("--setgroups=");
          
          				int sz = gids.length;
          				for (int i = 0; i < sz; i++) {
          					if (i != 0) {
          						sb.append(',');
          					}
          					sb.append(gids[i]);
          				}
          
          				argsForZygote.add(sb.toString());
          			}
          
          			if (niceName != null) {
          				argsForZygote.add("--nice-name=" + niceName);
          			}
          
          			argsForZygote.add(processClass);
          
          			if (extraArgs != null) {
          				for (String arg : extraArgs) {
          					argsForZygote.add(arg);
          				}
          			}
          
          			pid = zygoteSendArgsAndGetPid(argsForZygote);
          		}
          	}
          
          	......
          }
                  這個函數將創建進程的參數放到argsForZygote列表中去,如參數"--runtime-init"表示要為新創建的進程初始化運行時庫,然后調用zygoteSendAndGetPid函數進一步操作。

           

                  Step 4. Process.zygoteSendAndGetPid

                  這個函數定義在frameworks/base/core/java/android/os/Process.java文件中:

          public class Process {
          	......
          
          	private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
          			throws ZygoteStartFailedEx {
          		int pid;
          
          		openZygoteSocketIfNeeded();
          
          		try {
          			/**
          			* See com.android.internal.os.ZygoteInit.readArgumentList()
          			* Presently the wire format to the zygote process is:
          			* a) a count of arguments (argc, in essence)
          			* b) a number of newline-separated argument strings equal to count
          			*
          			* After the zygote process reads these it will write the pid of
          			* the child or -1 on failure.
          			*/
          
          			sZygoteWriter.write(Integer.toString(args.size()));
          			sZygoteWriter.newLine();
          
          			int sz = args.size();
          			for (int i = 0; i < sz; i++) {
          				String arg = args.get(i);
          				if (arg.indexOf('\n') >= 0) {
          					throw new ZygoteStartFailedEx(
          						"embedded newlines not allowed");
          				}
          				sZygoteWriter.write(arg);
          				sZygoteWriter.newLine();
          			}
          
          			sZygoteWriter.flush();
          
          			// Should there be a timeout on this?
          			pid = sZygoteInputStream.readInt();
          
          			if (pid < 0) {
          				throw new ZygoteStartFailedEx("fork() failed");
          			}
          		} catch (IOException ex) {
          			......
          		}
          
          		return pid;
          	}
          
          	......
          }
                   這里的sZygoteWriter是一個Socket寫入流,是由openZygoteSocketIfNeeded函數打開的:

           

          public class Process {
          	......
          
          	/**
          	* Tries to open socket to Zygote process if not already open. If
          	* already open, does nothing.  May block and retry.
          	*/
          	private static void openZygoteSocketIfNeeded()
          			throws ZygoteStartFailedEx {
          
          		int retryCount;
          
          		if (sPreviousZygoteOpenFailed) {
          			/*
          			* If we've failed before, expect that we'll fail again and
          			* don't pause for retries.
          			*/
          			retryCount = 0;
          		} else {
          			retryCount = 10;
          		}
          	
          		/*
          		* See bug #811181: Sometimes runtime can make it up before zygote.
          		* Really, we'd like to do something better to avoid this condition,
          		* but for now just wait a bit...
          		*/
          		for (int retry = 0
          			; (sZygoteSocket == null) && (retry < (retryCount + 1))
          			; retry++ ) {
          
          				if (retry > 0) {
          					try {
          						Log.i("Zygote", "Zygote not up yet, sleeping...");
          						Thread.sleep(ZYGOTE_RETRY_MILLIS);
          					} catch (InterruptedException ex) {
          						// should never happen
          					}
          				}
          
          				try {
          					sZygoteSocket = new LocalSocket();
          					sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
          						LocalSocketAddress.Namespace.RESERVED));
          
          					sZygoteInputStream
          						= new DataInputStream(sZygoteSocket.getInputStream());
          
          					sZygoteWriter =
          						new BufferedWriter(
          						new OutputStreamWriter(
          						sZygoteSocket.getOutputStream()),
          						256);
          
          					Log.i("Zygote", "Process: zygote socket opened");
          
          					sPreviousZygoteOpenFailed = false;
          					break;
          				} catch (IOException ex) {
          					......
          				}
          		}
          
          		......
          	}
          
          	......
          }
                  這個Socket由frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中的ZygoteInit類在runSelectLoopMode函數偵聽的。
                  Step 5. ZygoteInit.runSelectLoopMode
                  這個函數定義在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java文件中:

           

          public class ZygoteInit {
          	......
          
          	/**
          	* Runs the zygote process's select loop. Accepts new connections as
          	* they happen, and reads commands from connections one spawn-request's
          	* worth at a time.
          	*
          	* @throws MethodAndArgsCaller in a child process when a main() should
          	* be executed.
          	*/
          	private static void runSelectLoopMode() throws MethodAndArgsCaller {
          		ArrayList<FileDescriptor> fds = new ArrayList();
          		ArrayList<ZygoteConnection> peers = new ArrayList();
          		FileDescriptor[] fdArray = new FileDescriptor[4];
          
          		fds.add(sServerSocket.getFileDescriptor());
          		peers.add(null);
          
          		int loopCount = GC_LOOP_COUNT;
          		while (true) {
          			int index;
          			/*
          			* Call gc() before we block in select().
          			* It's work that has to be done anyway, and it's better
          			* to avoid making every child do it.  It will also
          			* madvise() any free memory as a side-effect.
          			*
          			* Don't call it every time, because walking the entire
          			* heap is a lot of overhead to free a few hundred bytes.
          			*/
          			if (loopCount <= 0) {
          				gc();
          				loopCount = GC_LOOP_COUNT;
          			} else {
          				loopCount--;
          			}
          
          
          			try {
          				fdArray = fds.toArray(fdArray);
          				index = selectReadable(fdArray);
          			} catch (IOException ex) {
          				throw new RuntimeException("Error in select()", ex);
          			}
          
          			if (index < 0) {
          				throw new RuntimeException("Error in select()");
          			} else if (index == 0) {
          				ZygoteConnection newPeer = acceptCommandPeer();
          				peers.add(newPeer);
          				fds.add(newPeer.getFileDesciptor());
          			} else {
          				boolean done;
          				done = peers.get(index).runOnce();
          
          				if (done) {
          					peers.remove(index);
          					fds.remove(index);
          				}
          			}
          		}
          	}
          
          	......
          }
                  當Step 4將數據通過Socket接口發送出去后,就會下面這個語句:

           

          done = peers.get(index).runOnce();
                  這里從peers.get(index)得到的是一個ZygoteConnection對象,表示一個Socket連接,因此,接下來就是調用ZygoteConnection.runOnce函數進一步處理了。

           

                  Step 6. ZygoteConnection.runOnce

                  這個函數定義在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:

          class ZygoteConnection {
          	......
          
          	boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
          		String args[];
          		Arguments parsedArgs = null;
          		FileDescriptor[] descriptors;
          
          		try {
          			args = readArgumentList();
          			descriptors = mSocket.getAncillaryFileDescriptors();
          		} catch (IOException ex) {
          			......
          			return true;
          		}
          
          		......
          
          		/** the stderr of the most recent request, if avail */
          		PrintStream newStderr = null;
          
          		if (descriptors != null && descriptors.length >= 3) {
          			newStderr = new PrintStream(
          				new FileOutputStream(descriptors[2]));
          		}
          
          		int pid;
          		
          		try {
          			parsedArgs = new Arguments(args);
          
          			applyUidSecurityPolicy(parsedArgs, peer);
          			applyDebuggerSecurityPolicy(parsedArgs);
          			applyRlimitSecurityPolicy(parsedArgs, peer);
          			applyCapabilitiesSecurityPolicy(parsedArgs, peer);
          
          			int[][] rlimits = null;
          
          			if (parsedArgs.rlimits != null) {
          				rlimits = parsedArgs.rlimits.toArray(intArray2d);
          			}
          
          			pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
          				parsedArgs.gids, parsedArgs.debugFlags, rlimits);
          		} catch (IllegalArgumentException ex) {
          			......
          		} catch (ZygoteSecurityException ex) {
          			......
          		}
          
          		if (pid == 0) {
          			// in child
          			handleChildProc(parsedArgs, descriptors, newStderr);
          			// should never happen
          			return true;
          		} else { /* pid != 0 */
          			// in parent...pid of < 0 means failure
          			return handleParentProc(pid, descriptors, parsedArgs);
          		}
          	}
          
          	......
          }
                   真正創建進程的地方就是在這里了:

           

          pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid,
          	parsedArgs.gids, parsedArgs.debugFlags, rlimits);
                  有Linux開發經驗的讀者很容易看懂這個函數調用,這個函數會創建一個進程,而且有兩個返回值,一個是在當前進程中返回的,一個是在新創建的進程中返回,即在當前進程的子進程中返回,在當前進程中的返回值就是新創建的子進程的pid值,而在子進程中的返回值是0。因為我們只關心創建的新進程的情況,因此,我們沿著子進程的執行路徑繼續看下去:

           

              if (pid == 0) {
          	// in child
          	handleChildProc(parsedArgs, descriptors, newStderr);
          	// should never happen
          	return true;
              } else { /* pid != 0 */
          	......
              }
                  這里就是調用handleChildProc函數了。

           

                  Step 7. ZygoteConnection.handleChildProc
                  這個函數定義在frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java文件中:

          class ZygoteConnection {
          	......
          
          	private void handleChildProc(Arguments parsedArgs,
          			FileDescriptor[] descriptors, PrintStream newStderr)
          			throws ZygoteInit.MethodAndArgsCaller {
          		......
          
          		if (parsedArgs.runtimeInit) {
          			RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
          		} else {
          			......
          		}
          	}
          
          	......
          }
                  由于在前面的Step 3中,指定了"--runtime-init"參數,表示要為新創建的進程初始化運行時庫,因此,這里的parseArgs.runtimeInit值為true,于是就繼續執行RuntimeInit.zygoteInit進一步處理了。

           

                  Step 8. RuntimeInit.zygoteInit

                  這個函數定義在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

          public class RuntimeInit {
          	......
          
          	public static final void zygoteInit(String[] argv)
          			throws ZygoteInit.MethodAndArgsCaller {
          		// TODO: Doing this here works, but it seems kind of arbitrary. Find
          		// a better place. The goal is to set it up for applications, but not
          		// tools like am.
          		System.setOut(new AndroidPrintStream(Log.INFO, "System.out"));
          		System.setErr(new AndroidPrintStream(Log.WARN, "System.err"));
          
          		commonInit();
          		zygoteInitNative();
          
          		int curArg = 0;
          		for ( /* curArg */ ; curArg < argv.length; curArg++) {
          			String arg = argv[curArg];
          
          			if (arg.equals("--")) {
          				curArg++;
          				break;
          			} else if (!arg.startsWith("--")) {
          				break;
          			} else if (arg.startsWith("--nice-name=")) {
          				String niceName = arg.substring(arg.indexOf('=') + 1);
          				Process.setArgV0(niceName);
          			}
          		}
          
          		if (curArg == argv.length) {
          			Slog.e(TAG, "Missing classname argument to RuntimeInit!");
          			// let the process exit
          			return;
          		}
          
          		// Remaining arguments are passed to the start class's static main
          
          		String startClass = argv[curArg++];
          		String[] startArgs = new String[argv.length - curArg];
          
          		System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);
          		invokeStaticMain(startClass, startArgs);
          	}
          
          	......
          }
                  這里有兩個關鍵的函數調用,一個是zygoteInitNative函數調用,一個是invokeStaticMain函數調用,前者就是執行Binder驅動程序初始化的相關工作了,正是由于執行了這個工作,才使得進程中的Binder對象能夠順利地進行Binder進程間通信,而后一個函數調用,就是執行進程的入口函數,這里就是執行startClass類的main函數了,而這個startClass即是我們在Step 1中傳進來的"android.app.ActivityThread"值,表示要執行android.app.ActivityThread類的main函數。

           

                  我們先來看一下zygoteInitNative函數的調用過程,然后再回到RuntimeInit.zygoteInit函數中來,看看它是如何調用android.app.ActivityThread類的main函數的。

                  step 9. RuntimeInit.zygoteInitNative

                  這個函數定義在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

          public class RuntimeInit {
          	......
          
          	public static final native void zygoteInitNative();
          
          	......
          }
                  這里可以看出,函數zygoteInitNative是一個Native函數,實現在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

           

          static void com_android_internal_os_RuntimeInit_zygoteInit(JNIEnv* env, jobject clazz)
          {
              gCurRuntime->onZygoteInit();
          }

           

                  這里它調用了全局變量gCurRuntime的onZygoteInit函數,這個全局變量的定義在frameworks/base/core/jni/AndroidRuntime.cpp文件開頭的地方:

          static AndroidRuntime* gCurRuntime = NULL;
          
                  這里可以看出,它的類型為AndroidRuntime,它是在AndroidRuntime類的構造函數中初始化的,AndroidRuntime類的構造函數也是定義在frameworks/base/core/jni/AndroidRuntime.cpp文件中:

           

          AndroidRuntime::AndroidRuntime()
          {
              ......
          
              assert(gCurRuntime == NULL);        // one per process
              gCurRuntime = this;
          }
          
                  那么這個AndroidRuntime類的構造函數又是什么時候被調用的呢?AndroidRuntime類的聲明在frameworks/base/include/android_runtime/AndroidRuntime.h文件中,如果我們打開這個文件會看到,它是一個虛擬類,也就是我們不能直接創建一個AndroidRuntime對象,只能用一個AndroidRuntime類的指針來指向它的某一個子類,這個子類就是AppRuntime了,它定義在frameworks/base/cmds/app_process/app_main.cpp文件中:

           

          int main(int argc, const char* const argv[])
          {
          	......
          
          	AppRuntime runtime;
          	
          	......
          }
                  而AppRuntime類繼續了AndroidRuntime類,它也是定義在frameworks/base/cmds/app_process/app_main.cpp文件中:
          class AppRuntime : public AndroidRuntime
          {
          	......
          
          };
          
                  因此,在前面的com_android_internal_os_RuntimeInit_zygoteInit函數,實際是執行了AppRuntime類的onZygoteInit函數。

           

                  Step 10. AppRuntime.onZygoteInit
                  這個函數定義在frameworks/base/cmds/app_process/app_main.cpp文件中:

          class AppRuntime : public AndroidRuntime
          {
          	......
          
          	virtual void onZygoteInit()
          	{
          		sp<ProcessState> proc = ProcessState::self();
          		if (proc->supportsProcesses()) {
          			LOGV("App process: starting thread pool.\n");
          			proc->startThreadPool();
          		}
          	}
          
          	......
          };
                  這里它就是調用ProcessState::startThreadPool啟動線程池了,這個線程池中的線程就是用來和Binder驅動程序進行交互的了。
                  Step 11. ProcessState.startThreadPool
                  這個函數定義在frameworks/base/libs/binder/ProcessState.cpp文件中:

           

          void ProcessState::startThreadPool()
          {
          	AutoMutex _l(mLock);
          	if (!mThreadPoolStarted) {
          		mThreadPoolStarted = true;
          		spawnPooledThread(true);
          	}
          }
                  ProcessState類是Binder進程間通信機制的一個基礎組件,它的作用可以參考淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析這三篇文章。這里它調用spawnPooledThread函數進一步處理。

           

                  Step 12. ProcessState.spawnPooledThread

                  這個函數定義在frameworks/base/libs/binder/ProcessState.cpp文件中:

          void ProcessState::spawnPooledThread(bool isMain)
          {
              if (mThreadPoolStarted) {
                  int32_t s = android_atomic_add(1, &mThreadPoolSeq);
                  char buf[32];
                  sprintf(buf, "Binder Thread #%d", s);
                  LOGV("Spawning new pooled thread, name=%s\n", buf);
                  sp<Thread> t = new PoolThread(isMain);
                  t->run(buf);
              }
          }
          
                  這里它會創建一個PoolThread線程類,然后執行它的run函數,最終就會執行PoolThread類的threadLoop函數了。

           

                  Step 13. PoolThread.threadLoop

                  這個函數定義在frameworks/base/libs/binder/ProcessState.cpp文件中:

          class PoolThread : public Thread
          {
          public:
              PoolThread(bool isMain)
                  : mIsMain(isMain)
              {
              }
          
          protected:
              virtual bool threadLoop()
              {
                  IPCThreadState::self()->joinThreadPool(mIsMain);
                  return false;
              }
          
              const bool mIsMain;
          };
          
                  這里它執行了IPCThreadState::joinThreadPool函數進一步處理。IPCThreadState也是Binder進程間通信機制的一個基礎組件,它的作用可以參考淺談Android系統進程間通信(IPC)機制Binder中的Server和Client獲得Service Manager接口之路Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析Android系統進程間通信(IPC)機制Binder中的Client獲得Server遠程接口過程源代碼分析這三篇文章。

           

                  Step 14. IPCThreadState.joinThreadPool

                  這個函數定義在frameworks/base/libs/binder/IPCThreadState.cpp文件中:

          void IPCThreadState::joinThreadPool(bool isMain)
          {
          	......
          
          	mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
          
          	......
          
          	status_t result;
          	do {
          		int32_t cmd;
          
          		......
          
          		// now get the next command to be processed, waiting if necessary
          		result = talkWithDriver();
          		if (result >= NO_ERROR) {
          			size_t IN = mIn.dataAvail();
          			if (IN < sizeof(int32_t)) continue;
          			cmd = mIn.readInt32();
          			......
          
          			result = executeCommand(cmd);
          		}
          
          		......
          	} while (result != -ECONNREFUSED && result != -EBADF);
          
          	......
          	
          	mOut.writeInt32(BC_EXIT_LOOPER);
          	talkWithDriver(false);
          }
                  這個函數首先告訴Binder驅動程序,這條線程要進入循環了:

           

          mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
                  然后在中間的while循環中通過talkWithDriver不斷與Binder驅動程序進行交互,以便獲得Client端的進程間調用:

           

          result = talkWithDriver();
                  獲得了Client端的進程間調用后,就調用excuteCommand函數來處理這個請求:

           

          result = executeCommand(cmd);
                  最后,線程退出時,也會告訴Binder驅動程序,它退出了,這樣Binder驅動程序就不會再在Client端的進程間調用分發給它了:

           

          mOut.writeInt32(BC_EXIT_LOOPER);
          talkWithDriver(false);
                  我們再來看看talkWithDriver函數的實現。

           

                  Step 15. talkWithDriver

                  這個函數定義在frameworks/base/libs/binder/IPCThreadState.cpp文件中:

          status_t IPCThreadState::talkWithDriver(bool doReceive)
          {
          	......
          
          	binder_write_read bwr;
          
          	// Is the read buffer empty?
          	const bool needRead = mIn.dataPosition() >= mIn.dataSize();
          
          	// We don't want to write anything if we are still reading
          	// from data left in the input buffer and the caller
          	// has requested to read the next data.
          	const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
          
          	bwr.write_size = outAvail;
          	bwr.write_buffer = (long unsigned int)mOut.data();
          
          	// This is what we'll read.
          	if (doReceive && needRead) {
          		bwr.read_size = mIn.dataCapacity();
          		bwr.read_buffer = (long unsigned int)mIn.data();
          	} else {
          		bwr.read_size = 0;
          	}
          
          	......
          
          	// Return immediately if there is nothing to do.
          	if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
          
          	bwr.write_consumed = 0;
          	bwr.read_consumed = 0;
          	status_t err;
          	do {
          		......
          #if defined(HAVE_ANDROID_OS)
          		if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
          			err = NO_ERROR;
          		else
          			err = -errno;
          #else
          		err = INVALID_OPERATION;
          #endif
          		......
          		}
          	} while (err == -EINTR);
          
          	....
          
          	if (err >= NO_ERROR) {
          		if (bwr..write_consumed > 0) {
          			if (bwr.write_consumed < (ssize_t)mOut.dataSize())
          				mOut.remove(0, bwr.write_consumed);
          			else
          				mOut.setDataSize(0);
          		}
          		if (bwr.read_consumed > 0) {
          			mIn.setDataSize(bwr.read_consumed);
          			mIn.setDataPosition(0);
          		}
          		......
          		return NO_ERROR;
          	}
          
          	return err;
          }
                  這個函數的具體作用可以參考Android系統進程間通信(IPC)機制Binder中的Server啟動過程源代碼分析一文,它只要就是通過ioctl文件操作函數來和Binder驅動程序交互的了:

           

          ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
                  有了這個線程池之后,我們在開發Android應用程序的時候,當我們要和其它進程中進行通信時,只要定義自己的Binder對象,然后把這個Binder對象的遠程接口通過其它途徑傳給其它進程后,其它進程就可以通過這個Binder對象的遠程接口來調用我們的應用程序進程的函數了,它不像我們在C++層實現Binder進程間通信機制的Server時,必須要手動調用IPCThreadState.joinThreadPool函數來進入一個無限循環中與Binder驅動程序交互以便獲得Client端的請求,這樣就實現了我們在文章開頭處說的Android應用程序進程天然地支持Binder進程間通信機制。

           

                  細心的讀者可能會發現,從Step 1到Step 9,都是在Android應用程序框架層運行的,而從Step 10到Step 15,都是在Android系統運行時庫層運行的,這兩個層次中的Binder進程間通信機制的接口一個是用Java來實現的,而別一個是用C++來實現的,這兩者是如何協作的呢?這就是通過JNI層來實現的了,具體可以參考Android系統進程間通信Binder機制在應用程序框架層的Java接口源代碼分析一文。

                  回到Step 8中的RuntimeInit.zygoteInit函數中,在初始化完成Binder進程間通信機制的基礎設施后,它接著就要進入進程的入口函數了。

                  Step 16. RuntimeInit.invokeStaticMain

                  這個函數定義在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java文件中:

          public class ZygoteInit {
          	......
          
          	static void invokeStaticMain(ClassLoader loader,
          			String className, String[] argv)
          			throws ZygoteInit.MethodAndArgsCaller {
          		Class<?> cl;
          
          		try {
          			cl = loader.loadClass(className);
          		} catch (ClassNotFoundException ex) {
          			......
          		}
          
          		Method m;
          		try {
          			m = cl.getMethod("main", new Class[] { String[].class });
          		} catch (NoSuchMethodException ex) {
          			......
          		} catch (SecurityException ex) {
          			......
          		}
          
          		int modifiers = m.getModifiers();
          		......
          
          		/*
          		* This throw gets caught in ZygoteInit.main(), which responds
          		* by invoking the exception's run() method. This arrangement
          		* clears up all the stack frames that were required in setting
          		* up the process.
          		*/
          		throw new ZygoteInit.MethodAndArgsCaller(m, argv);
          	}
          
          	......
          }
                  前面我們說過,這里傳進來的參數className字符串值為"android.app.ActivityThread",這里就通ClassLoader.loadClass函數將它加載到進程中:

           

          cl = loader.loadClass(className);
                  然后獲得它的靜態成員函數main:

           

          m = cl.getMethod("main", new Class[] { String[].class });
                  函數最后并沒有直接調用這個靜態成員函數main,而是通過拋出一個異常ZygoteInit.MethodAndArgsCaller,然后讓ZygoteInit.main函數在捕獲這個異常的時候再調用android.app.ActivityThread類的main函數。為什么要這樣做呢?注釋里面已經講得很清楚了,它是為了清理堆棧的,這樣就會讓android.app.ActivityThread類的main函數覺得自己是進程的入口函數,而事實上,在執行android.app.ActivityThread類的main函數之前,已經做了大量的工作了。

           

                  我們看看ZygoteInit.main函數在捕獲到這個異常的時候做了什么事:

          public class ZygoteInit {
          	......
          
          	public static void main(String argv[]) {
          		try {
          			......
          		} catch (MethodAndArgsCaller caller) {
          			caller.run();
          		} catch (RuntimeException ex) {
          			......
          		}
          	}
          
          	......
          }
                  它執行MethodAndArgsCaller的run函數:

           

          public class ZygoteInit {
          	......
          
          	public static class MethodAndArgsCaller extends Exception
          			implements Runnable {
          		/** method to call */
          		private final Method mMethod;
          
          		/** argument array */
          		private final String[] mArgs;
          
          		public MethodAndArgsCaller(Method method, String[] args) {
          			mMethod = method;
          			mArgs = args;
          		}
          
          		public void run() {
          			try {
          				mMethod.invoke(null, new Object[] { mArgs });
          			} catch (IllegalAccessException ex) {
          				......
          			} catch (InvocationTargetException ex) {
          				......
          			}
          		}
          	}
          
          	......
          }
                  這里的成員變量mMethod和mArgs都是在前面構造異常對象時傳進來的,這里的mMethod就對應android.app.ActivityThread類的main函數了,于是最后就通過下面語句執行這個函數:

           

          mMethod.invoke(null, new Object[] { mArgs });
                  這樣,android.app.ActivityThread類的main函數就被執行了。

           

                  Step 17. ActivityThread.main

                  這個函數定義在frameworks/base/core/java/android/app/ActivityThread.java文件中:

          public final class ActivityThread {
          	......
          
          	public static final void main(String[] args) {
          		SamplingProfilerIntegration.start();
          
          		Process.setArgV0("<pre-initialized>");
          
          		Looper.prepareMainLooper();
          		if (sMainThreadHandler == null) {
          			sMainThreadHandler = new Handler();
          		}
          
          		ActivityThread thread = new ActivityThread();
          		thread.attach(false);
          
          		if (false) {
          			Looper.myLooper().setMessageLogging(new
          				LogPrinter(Log.DEBUG, "ActivityThread"));
          		}
          		Looper.loop();
          
          		if (Process.supportsProcesses()) {
          			throw new RuntimeException("Main thread loop unexpectedly exited");
          		}
          
          		thread.detach();
          		String name = (thread.mInitialApplication != null)
          			? thread.mInitialApplication.getPackageName()
          			: "<unknown>";
          		Slog.i(TAG, "Main thread of " + name + " is now exiting");
          	}
          
          	......
          }
                  從這里我們可以看出,這個函數首先會在進程中創建一個ActivityThread對象:

           

          ActivityThread thread = new ActivityThread();
                  然后進入消息循環中:

           

          Looper.loop();
                  這樣,我們以后就可以在這個進程中啟動Activity或者Service了。

           

                  至此,Android應用程序進程啟動過程的源代碼就分析完成了,它除了指定新的進程的入口函數是ActivityThread的main函數之外,還為進程內的Binder對象提供了Binder進程間通信機制的基礎設施,由此可見,Binder進程間通信機制在Android系統中是何等的重要,而且是無處不在,想進一步學習Android系統的Binder進程間通信機制,請參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文。

          作者:Luoshengyang 發表于2011-9-9 1:01:32 原文鏈接
          閱讀:8086 評論:15 查看評論
          posted on 2012-04-17 21:32 mixer-a 閱讀(754) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 天门市| 安溪县| 温宿县| 密山市| 平和县| 石泉县| 吉林省| 光山县| 昭通市| 阳泉市| 潜江市| 八宿县| 雅江县| 酒泉市| 遂宁市| 林芝县| 静宁县| 仪陇县| 建宁县| 林甸县| 正宁县| 芦山县| 平湖市| 宁陕县| 陆河县| 托克托县| 南陵县| 鲜城| 安宁市| 铁岭市| 古蔺县| 阿克陶县| 射洪县| 宝鸡市| 包头市| 射阳县| 涡阳县| 溆浦县| 陆川县| 正宁县| 马关县|