【23】Android 应用程序入口探究
目录
前言
Android 框架
Android系统启动流程
装载机层
内核层
原生API层
框架层(Framework)
应用层
Android应用程序打开流程
重要声明
参考鸣谢
前言
如果你和我一样刚刚接触安卓不久,又恰巧学过其他编程,那么你多半会有个和我一样的疑问缠绕心头:Android 程序的入口到底在哪里?
我们知道,Android开发采用的编程语言是 Java 或 Kotlin,由于目前使用的是 Java ,这里仅说 Java。以往我们写 Java程序都会有一个入口函数main;而我们之前写的 Demo,程序都是从 Activity 的 onCreate( ) 方法中开始执行,那么它就我们Anroid APP程序的入口吗 ?
答案是 否定的。
我们都知道我们 Android 应用程序是运行在 Android系统 之上的,即先有 Android系统,才能运行我们的 app。
下面我们先看了解下 Android 的整体框架及 Android 系统的启动流程:
Android 框架
Android系统启动流程
装载机层
- Boot Rom:当手机处于关机状态时,长按开机键开机,会引导芯片开始从固化在 ROM 里的代码开始执行,然后加载引导程序到RAM
- Boot Loader:启动 Android 系统之前的引导程序,主要是检查 RAM,初始化参数等
内核层
Kernel层指的就是 Android 的 Linux内核层,其启动流程如下:
- 启动 swapper进程(PID = 0),这是系统初始化过程内核创建的第一个进程,用于初始化进程管理,内存管理,加载Display,Camera,Binder等驱动相关工作
- 启动 kthreadd 进程(PID = 2),它会创建内核工作 线程 kworkder,软中断 线程ksoftirqd、thermal 等内核守护进程。
kthreadd 是所有内核进程的鼻祖。
原生API层
这里 Native层 主要包括 init进程(PID = 1) 孵化的用户空间的守护进程,HAL 层以及开机动画等。
- init 进程会孵化出 ueventd,logd,healthd,installd,adbd,lmkd 等用户守护进程;
- init 进度即将启动 ServiceManager(Binder 服务管家),bootanim(开机动画)等重要服务。
- init 进程孵化出 Zygote进程,Zygote进程是 Android 系统第一个 Java 进程(虚拟机进程)。
Init 是所有用户空间进程的鼻祖。
Zygote进程是所有 Java 进程的父进程。
框架层(Framework)
Zygote 进程,是由 init 进程通过解析 init.rc 文件后 fork( ) 生成的,它主要包括以下内
- 加载 ZygoteInit 类,注册 Zygote Socket 服务端套接字
- 加载虚拟机
- 提前加载类 preloadClasses
- 提前加载资源 preloadResouces
System Server 进程,是由 Zygote 进程 fork( ) 而来
- System Server 是Zygote 孵化的第一个进程。
- System Server 负责启动和管理整个 Java framework,包含 ActivityManager,WindowManager,PackageManager,PowerManager 等服务。
Media Server 进程,是由 init 进程 fork( ) 而来
负责启动和管理整个 C++ framework,包含 AudioFlinger,Camera Service 等服务。
应用层
- Zygote 孵化进程第的一个 App进程 为 Launcher进程,也就是我们的桌面进程。
- Zygote进程 也会创建 Browser,Phone,Email等应用进程。也就是说所有的应用都是进程由 Zygote 进程 fork() 生成的。而且上层的进程全部由下层的进程进行管理,包括但不限于界面的注册,跳转,消息的传递。
Android应用程序打开流程
重要声明
本次Android源码阅读的版本是 2014-09-06- 索引:棒棒糖 - 5.0.0_r2
为什么不看最新的源码呢,因为资料少..目前还真啃不动
主界面 Launcher 其实也是一个 Activity,它存在击 icon 的事件OnClick()
// 代码节选:// Launcher.java --- 2428 /** * Launches the intent referred by the clicked shortcut. * * @param v The view representing the clicked shortcut. */ public void onClick(View v) { // Make sure that rogue clicks don't get through while allapps is launching, or after the // view has detached (it's possible for this to happen if the view is removed mid touch). if (v.getWindowToken() == null) { return; } if (!mWorkspace.isFinishedSwitchingState()) { return; } if (v instanceof Workspace) { if (mWorkspace.isInOverviewMode()) { mWorkspace.exitOverviewMode(true); } return; } if (v instanceof CellLayout) { if (mWorkspace.isInOverviewMode()) { mWorkspace.exitOverviewMode(mWorkspace.indexOfChild(v), true); } } Object tag = v.getTag(); if (tag instanceof ShortcutInfo) { onClickAppShortcut(v); } else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) { onClickFolderIcon(v); } } else if (v == mAllAppsButton) { onClickAllAppsButton(v); } else if (tag instanceof AppInfo) { startAppShortcutOrInfoActivity(v); } else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) { onClickPendingWidget((PendingAppWidgetHostView) v); } } }
OnClick 事件会调用 startAppShortcutOrInfoActivity ()
// 代码节选:// Launcher.java --- 2629private void startAppShortcutOrInfoActivity(View v) { Object tag = v.getTag(); final ShortcutInfo shortcut; final Intent intent; if (tag instanceof ShortcutInfo) { shortcut = (ShortcutInfo) tag; intent = shortcut.intent; int[] pos = new int[2]; v.getLocationOnScreen(pos); intent.setSourceBounds(new Rect(pos[0], pos[1], pos[0] + v.getWidth(), pos[1] + v.getHeight())); } else if (tag instanceof AppInfo) { shortcut = null; intent = ((AppInfo) tag).intent; } else { throw new IllegalArgumentException("Input must be a Shortcut or AppInfo"); } boolean success = startActivitySafely(v, intent, tag); mStats.recordLaunch(intent, shortcut); if (success && v instanceof BubbleTextView) { mWaitingForResume = (BubbleTextView) v; mWaitingForResume.setStayPressed(true); } }
这里调用了 startActivitySafely() 并通过 Binder IPC 机制 调用 ActivityManagerService.java 中的 startActivity (Intent)
// 代码节选:// ActivityManagerService.java --- 3589 @Override public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle options) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profilerInfo, options, UserHandle.getCallingUserId()); }
ActivityManagerService 会执行如下操作:
- 通过 PackageManager 的 resolveIntent () 收集这个 intent 对象的指向信息,并将指向信息被存储在一个 intent 对象中。
// 代码节选:// ActivityManagerService.java --- 3341ResolveInfo info = AppGlobals.getPackageManager().resolveIntent( intent, intent.resolveTypeIfNeeded(mContext.getContentResolver()), flags, userId);
- 通过 grantUriPermissionLocked () 方法来验证用户是否有足够的权限去调用该 intent 对象指向的 Activity.
// 代码节选:// ActivityManagerService.java --- 7538// grantUriPermissionLocked () 在 7388 处/** * @param uri This uri must NOT contain an embedded userId. * @param userId The userId in which the uri is to be resolved. */ @Override public void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, final int modeFlags, int userId) { enforceNotIsolatedCaller("grantUriPermission"); GrantUri grantUri = new GrantUri(userId, uri, false); synchronized(this) { final ProcessRecord r = getRecordForAppLocked(caller); if (r == null) { throw new SecurityException("Unable to find app for caller " + caller + " when granting permission to uri " + grantUri); } if (targetPkg == null) { throw new IllegalArgumentException("null target"); } if (grantUri == null) { throw new IllegalArgumentException("null uri"); } Preconditions.checkFlagsArgument(modeFlags, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION); grantUriPermissionLocked(r.uid, targetPkg, grantUri, modeFlags, null, UserHandle.getUserId(r.uid)); } }
- 如果有权限,ActivityManagerService 会检查并在新的 task 中启动目标 activity。
这时需要先检查这个进程的 ProcessRecord 是否存在了。(ProcessRecord 是用于描述进程的数据结构对象)
如果 ProcessRecord 是 null, ActivityManagerService 会创建新的进程来实例化目标 activity.
为了启动 App 并使其 Activity 进入 resumed 状态,需要先使当前运行的 Activity(也就是 Launcher) 进入 Paused 状态
ActivityManagerService 最终调用 overridePendingTransition( ) 执行(未严格验证)
// 代码摘取:// ActivityManagerService .java ---- 4700 @Override public void overridePendingTransition(IBinder token, String packageName, int enterAnim, int exitAnim) { synchronized(this) { ActivityRecord self = ActivityRecord.isInStackLocked(token); if (self == null) { return; } final long origId = Binder.clearCallingIdentity(); if (self.state == ActivityState.RESUMED || self.state == ActivityState.PAUSING) { mWindowManager.overridePendingAppTransition(packageName, enterAnim, exitAnim, null); } Binder.restoreCallingIdentity(origId); } }
之后又通过 Binder 通信 调用到 ApplicationThread 的 schedulePauseActivity( )向本地的消息循环中加入一个 H.PAUSE_ACTIVITY 的消息。
// 代码摘取:// ApplicationThread.java ---- 565 public final void schedulePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { sendMessage( finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY, token, (userLeaving ? 1 : 0) | (dontReport ? 2 : 0), configChanges); }
之后会通过 Handler 的子类 - H 发送消息,处理消息的逻辑在 ActivityThread.java 的 handleMessage( ) 中
// 代码摘取:// ActivityThread.java ---- 1269 public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); final ActivityClientRecord r = (ActivityClientRecord) msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case RELAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; handleRelaunchActivity(r); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; case PAUSE_ACTIVITY: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2, (msg.arg1&2) != 0); maybeSnapshot(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break; //... } if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what)); }
最终会调用 Activity 的 performPause () 方法
// 代码摘取:// Activity.java ---- 6040 final void performPause() { mDoReportFullyDrawn = false; mFragments.dispatchPause(); mCalled = false; onPause(); mResumed = false; if (!mCalled && getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.GINGERBREAD) { throw new SuperNotCalledException( "Activity " + mComponent.toShortString() + " did not call through to super.onPause()"); } mResumed = false; }
终于出现一个比较熟悉的身影了 onPause( )
之后在 handlePauseActivity ( ) 中调用 ActivityManagerNative.getDefault().activityPaused(token);
// 代码摘取:// Activitythread.java ---- 3149 private void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, int configChanges, boolean dontReport) { ActivityClientRecord r = mActivities.get(token); if (r != null) { //Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r); if (userLeaving) { performUserLeavingActivity(r); } r.activity.mConfigChangeFlags |= configChanges; performPauseActivity(token, finished, r.isPreHoneycomb()); // Make sure any pending writes are now committed. if (r.isPreHoneycomb()) { QueuedWork.waitToFinish(); } // Tell the activity manager we have paused. if (!dontReport) { try { ActivityManagerNative.getDefault().activityPaused(token); } catch (RemoteException ex) { } } mSomeActivitiesChanged = true; } }
通过 Binder 机制调用 ActivityManagerService 中的 activityPaused ( ) 方法,如下:
// 代码摘录://ActivityManagerService.java ---- 6435 @Override public final void activityPaused(IBinder token) { final long origId = Binder.clearCallingIdentity(); synchronized(this) { ActivityStack stack = ActivityRecord.getStackLocked(token); if (stack != null) { stack.activityPausedLocked(token, false); } } Binder.restoreCallingIdentity(origId); }
最终调用到 startProcessLocked ( )
该方法用以创建新的进程,通过 socket 通道传递参数给 Zygote 进程。Zygote 孵化自身,并调用 ZygoteInit.main () 方法来实例化 ActivityThread 对象并最终返回新进程的 pid。具体过程如下:
// 代码摘录:// ActivityManagerService.java ---- 2947 final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); }
接着会调用startProcessLocked ( )的重载方法:
// 代码摘录://ActivityManagerService.java ---- 3189 private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { //... // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. boolean isActivityProcess = (entryPoint == null); if (entryPoint == null) entryPoint = "android.app.ActivityThread"; checkTime(startTime, "startProcess: asking zygote to start proc"); Process.ProcessStartResult startResult = Process.start(entryPoint, app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); checkTime(startTime, "startProcess: returned from zygote!"); //... }
Process.start ( ) 实际上是调用 Zygote 来 fork( ) 一个新的进程,并且在最后会调用 ActivityThread 的 main () 方法。ActivityManagerService 所在的进程和 Zygote 所在的进程通过 Socket 通信,ZygoteInit 中循环侦听 Socket 连接:
// 代码摘录// ZygoteInit.java ---- 733/** * 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 runSelectLoop(String abiList) 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; 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(abiList); peers.add(newPeer); fds.add(newPeer.getFileDescriptor()); } else { boolean done; done = peers.get(index).runOnce(); if (done) { peers.remove(index); fds.remove(index); } } } }
可发现:
一旦建立 ZygoteConnection 即调用 runOnce( )
//代码摘录://ZygoteConnection.java ---- 142boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { //... checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); //... try { if (pid == 0) { // in child IoUtils.closeQuietly(serverPipeFd); serverPipeFd = null; handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr); // should never get here, the child is expected to either // throw ZygoteInit.MethodAndArgsCaller or exec(). return true; } else { // in parent...pid of < 0 means failure IoUtils.closeQuietly(childPipeFd); childPipeFd = null; return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs); } //...}
我们来看看 forkAndSpecialize ( )
//代码摘录://Zygote.java ---- 87 public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, String instructionSet, String appDataDir) { long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.preFork(); checkTime(startTime, "Zygote.preFork"); int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, instructionSet, appDataDir); checkTime(startTime, "Zygote.nativeForkAndSpecialize"); VM_HOOKS.postForkCommon(); checkTime(startTime, "Zygote.postForkCommon"); return pid; }
最终会去 fork( ) 进程,在子进程 (即 App 进程) 中执行 handleChildProc ( ) 方法
//代码摘录://ZygoteConnection.java ---- 855 /** * Handles post-fork setup of child proc, closing sockets as appropriate, * reopen stdio as appropriate, and ultimately throwing MethodAndArgsCaller * if successful or returning if failed. * * @param parsedArgs non-null; zygote args * @param descriptors null-ok; new file descriptors for stdio if available. * @param pipeFd null-ok; pipe for communication back to Zygote. * @param newStderr null-ok; stream to use for stderr until stdio * is reopened. * * @throws ZygoteInit.MethodAndArgsCaller on success to * trampoline to code that invokes static main. */ private void handleChildProc(Arguments parsedArgs, FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller { /** * By the time we get here, the native code has closed the two actual Zygote * socket connections, and substituted /dev/null in their place. The LocalSocket * objects still need to be closed properly. */ closeSocket(); ZygoteInit.closeServerSocket(); if (descriptors != null) { try { ZygoteInit.reopenStdio(descriptors[0], descriptors[1], descriptors[2]); for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } newStderr = System.err; } catch (IOException ex) { Log.e(TAG, "Error reopening stdio", ex); } } if (parsedArgs.niceName != null) { Process.setArgV0(parsedArgs.niceName); } if (parsedArgs.runtimeInit) { if (parsedArgs.invokeWith != null) { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, pipeFd, parsedArgs.remainingArgs); } else { RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, null /* classLoader */); } } else { String className; try { className = parsedArgs.remainingArgs[0]; } catch (ArrayIndexOutOfBoundsException ex) { logAndPrintError(newStderr, "Missing required class name argument", null); return; } String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; System.arraycopy(parsedArgs.remainingArgs, 1, mainArgs, 0, mainArgs.length); if (parsedArgs.invokeWith != null) { WrapperInit.execStandalone(parsedArgs.invokeWith, parsedArgs.classpath, className, mainArgs); } else { ClassLoader cloader; if (parsedArgs.classpath != null) { cloader = new PathClassLoader(parsedArgs.classpath, ClassLoader.getSystemClassLoader()); } else { cloader = ClassLoader.getSystemClassLoader(); } try { ZygoteInit.invokeStaticMain(cloader, className, mainArgs); } catch (RuntimeException ex) { logAndPrintError(newStderr, "Error starting.", ex); } } } }
注意到后面调用了 ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
本处即调用 ActivityThread 的 main () 方法
//代码摘录://ActivityThread.java ---- 5184 public static void main(String[] args) { SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); //初始化当前UserID Environment.initForCurrentUser(); // Set the reporter for event logging in libcore EventLogger.setReporter(new EventLoggingReporter()); Security.addProvider(new AndroidKeyStoreProvider()); // Make sure TrustedCertificateStore looks in the right place for CA certificates //设置当前用户CA证书的保存位置 final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId()); TrustedCertificateStore.setDefaultUserDirectory(configDir); //设置进程名 Process.setArgV0(""); //为主进程创建Looper Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); //发出创建ActivityThread的消息 thread.attach(false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } AsyncTask.init(); if (false) { Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread")); } //主线程进入无限循环状态,等待接收消息 Looper.loop(); throw new RuntimeException("Main thread loop unexpectedly exited"); }}
从这里开始,准备主线程的消息队列,并为 App 创建并配置一个 ActivityThread, 再通过 thread.attach ( ) 将 ActivityThead, ApplicationThread 与 ActivityManagerService 关联起来。
ActivityThread 随后依次调用 Looper.prepareLoop () 和 Looper.loop () 来开启消息循环
ActivityManagerService 通过 Binder 通知 ActivityThread 进行 App 中主线程的调度工作。
ActivityThread main( )逻辑如下:
大佬原图,可点击查看大图(ps:转自 3分钟看懂 Activity 启动流程)
参考鸣谢
Where is main() in Android?
Android 应用的真正入口是哪里?Seasoninthesun - 回答(强烈推荐)
Android系统架构开篇(强烈推荐)
3 分钟看懂 Activity 启动流程(强烈推荐)
Android 应用程序进程启动过程(强烈推荐)
Android 应用程序入口源码解析
ActivityThread的main方法究竟做了什么
资源下载
链接 提取码: b2cg
更多相关文章
- Android多进程app中Application回调onCreate()方法被执行多次分
- 如何降低android应用程序的耗电量
- 《Android系统源代码情景分析》连载回忆录:灵感之源
- android获取正在运行的应用程序