枕上从妨一夜睡,灯前读尽十年诗。这篇文章主要讲述Android Phone进程启动过程详解相关的知识,希望能为你提供帮助。
之前解决一个开机搜网慢的问题时,
发现由于Phone进程起来以后才会主动连接RILD,因而在一定程度上Phone进程启动的时间会影响网络状态注册的快慢。适当的将Phone进程提前,
可以将网络注册时间提前一点,
让状态栏中信号显示的时间提前。那么,
android中作为系统的核心进程之一,
Phone进程是如何启动的了?
本文参考代码为Android NN7.0, RIL运行机制请参考: Android RIL概述Telephony最开始创建的是
PhoneFactory
对象,
直接搜索源码,
可以看到在PhoneGlobals.java
创建时,
会调用PhoneFactory
对Telephony进行初始化操作:
/**
* Global state for the telephony subsystem when running in the primary
* phone process.
*/
public class PhoneGlobals extends ContextWrapper {public void onCreate() {
Log.v(LOG_TAG, "
!@
Boot_SVC : PhoneApp OnCrate"
);
// CallManager为空
if (mCM =
=
null) {
// Initialize the telephony framework
PhoneFactory.makeDefaultPhones(this);
// 创建CallManager实例
mCM =
CallManager.getInstance();
for (Phone phone : PhoneFactory.getPhones()) {
mCM.registerPhone(phone);
}
....
}}
那么,
PhoneGlobals
又是在哪里创建的了?
再次搜索代码,
可以看到在同一文件目录下,
有一个PhoneApp.java
文件:
@
Override
public void onCreate() {
Log.d("
PhoneApp"
, "
onCreate"
);
if (UserHandle.myUserId() =
=
0) {
// 创建PhoneGlobals实例
mPhoneGlobals =
new PhoneGlobals(this);
mPhoneGlobals.onCreate();
mTelephonyGlobals =
new TelephonyGlobals(this);
mTelephonyGlobals.onCreate();
} else {
Log.d("
PhoneApp"
, "
Phone app is created as userid not 0, there'
s no PhoneApp() Instance"
);
}
....
}
那么,
PhoneApp
这个类又是什么时候创建的?
我们知道,
每一个Android应用都有一个Application
与之对应,
它是在应用启动过程中创建的,
但是在这里搜索所有的源码,
也无法看到PhoneApp
创建的地方。联想到应用的启动过程,
APP的启动的入口是ActivityThread
,那么对于任何PhoneApp
这样的系统应用来说,
启动的入口也应该是ActivityThread
。不妨继续看看代码。打开Phone进程所在的源码路径:
/android/applications/sources/services/Telephony/
,查看应用对应的AndroidManefest.xml
文件:
<
manifest xmlns:android=
"
http://schemas.android.com/apk/res/android"
xmlns:androidprv=
"
http://schemas.android.com/apk/prv/res/android"
package=
"
com.android.phone"
android:versionCode=
"
1"
android:versionName=
"
1.0.0"
coreApp=
"
true"
android:sharedUserId=
"
android.uid.phone"
android:sharedUserLabel=
"
@
string/phoneAppLabel"
>
.....
<
application android:name=
"
PhoneApp"
android:persistent=
"
true"
android:hardwareAccelerated=
"
true"
android:label=
"
@
string/phoneAppLabel"
android:icon=
"
@
mipmap/ic_launcher_phone"
android:allowBackup=
"
false"
android:supportsRtl=
"
true"
android:usesCleartextTraffic=
"
true"
android:defaultToDeviceProtectedStorage=
"
true"
android:directBootAware=
"
true"
>
....
<
/application>
<
/manifest>
在
application
标签下面,
可以看到android:persistent=
"
true"
这个属性值,
看一看官方的文档怎么解释的:
android:persistent由此可见, Phone应用是系统常驻进程, 一旦起来后就会一直运行, 不会被杀死( 除非Phone进程自己发生了的运行时错误而崩溃) 。对于这类常驻进程,
Whether or not the application should remain running at all times — “true” if it should, and “false” if not. The default value is “false”. Applications should not normally set this flag; persistence mode is intended only for certain system applications.
ActivityManagerService
(以下简称AMS)会在初始化完成后,
主动启动。在SystemServer
初始化完系统的核心服务后,
会调用AMS的systemReady(Runnable r)
函数。ActivityManagerService.java
public void systemReady(final Runnable goingCallback) {synchronized (this) {// Only start up encryption-aware persistent apps;
once user is
// unlocked we'
ll come back around and start unaware apps
// 正是在这里,
phone进程被创建
startPersistentApps(PackageManager.MATCH_DIRECT_BOOT_AWARE);
// Start up initial activity.
mBooting =
true;
// Enable home activity for system user, so that the system can always boot
if (UserManager.isSplitSystemUser()) {
ComponentName cName =
new ComponentName(mContext, SystemUserHomeActivity.class);
try {
AppGlobals.getPackageManager().setComponentEnabledSetting(cName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0,
UserHandle.USER_SYSTEM);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
startHomeActivityLocked(currentUserId, "
systemReady"
);
}}
启动所有
PackageManager.MATCH_DIRECT_BOOT_AWARE
标志为true
的应用:
private void startPersistentApps(int matchFlags) {synchronized (this) {
try {
//获取系统所有常驻应用程序信息
final List<
ApplicationInfo>
apps =
AppGlobals.getPackageManager()
.getPersistentApplications(STOCK_PM_FLAGS | matchFlags).getList();
for (ApplicationInfo app : apps) {
if (!"
android"
.equals(app.packageName)) {
//加载应用
addAppLocked(app, false, null /* ABI override */);
}
}
} catch (RemoteException ex) {
}
}
}//添加应用程序进程到LRU列表中,
并创建进程
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
String abiOverride) {
ProcessRecord app;
if (!isolated) {
app =
getProcessRecordLocked(info.processName, info.uid, true);
} else {
app =
null;
}// 没有进程记录,
因此创建一个进程记录
if (app =
=
null) {
app =
newProcessRecordLocked(info, null, isolated, 0);
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
....if ((info.flags &
PERSISTENT_MASK) =
=
PERSISTENT_MASK) {
app.persistent =
true;
app.maxAdj =
ProcessList.PERSISTENT_PROC_ADJ;
}// 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);
// 进程入口为ActivityThread
if (entryPoint =
=
null) entryPoint =
"
android.app.ActivityThread"
;
//启动应用进程
if (app.thread =
=
null &
&
mPersistentStartingProcesses.indexOf(app) <
0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "
added application"
, app.processName, abiOverride,
null /* entryPoint */, null /* entryPointArgs */);
}return app;
}
准备创建应用进程:
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {Process.ProcessStartResult startResult =
null;
....startResult =
Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, aasaSeInfo !=
null ? new String(aasaSeInfo) : app.info.seinfo, //AASA--4 : changed orginal : only "
app.info.seinfo"
app.info.category, app.info.accessInfo,
requiredAbi, instructionSet,
app.info.dataDir, mountKnoxPoint, entryPointArgs);
....
}
Process.java 调用
Process.start()
,
创建一个新的进程, Telephony服务以及RIL相关代码都运行在此进程中:
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, category, accessInfo,
abi, instructionSet, appDataDir, mountKnoxPoint, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"
Starting VM process through Zygote failed"
);
throw new RuntimeException(
"
Starting VM process through Zygote failed"
, ex);
}
}
发送消息到zygote服务进程的socket端口, 请求创建新的进程:
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<
String>
argsForZygote =
new ArrayList<
String>
();
// --runtime-args, --setuid=
, --setgid=
,
// and --setgroups=
must go first
argsForZygote.add("
--runtime-args"
);
argsForZygote.add("
--setuid=
"
+
uid);
argsForZygote.add("
--setgid=
"
+
gid);
....
if (appDataDir !=
null) {
argsForZygote.add("
--app-data-dir=
"
+
appDataDir);
}
....
argsForZygote.add(processClass);
if (extraArgs !=
null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}//发送消息到zygote的socket端口,
请求创建新的进程
if (Zygote.isEnhancedZygoteASLREnabled) {
....
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
// End of isEnhancedZygoteASLREnabled case
} else {
// Original case
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
}
ZygoteConnection.java zygote进程接收到AMS的请求后, 由
ZygoteConnection
负责处理请求:
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {String args[];
Arguments parsedArgs =
null;
FileDescriptor[] descriptors;
try {
// 从socket中读取参数
args =
readArgumentList();
descriptors =
mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "
IOException on command socket "
+
ex.getMessage());
closeSocket();
return true;
}if (args =
=
null) {
// EOF reached.
closeSocket();
return true;
}int pid =
-1;
FileDescriptor childPipeFd =
null;
FileDescriptor serverPipeFd =
null;
...
try {
parsedArgs =
new Arguments(args);
//Zygote调用本地方法创建进程
pid =
Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir, parsedArgs.mountKnoxPoint);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "
Exception creating pipe"
, ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "
Invalid zygote arguments"
, ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"
Zygote security policy prevents request: "
, ex);
}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);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}
ZygoteInit.java 至此phone进程已经创建完成了, 但实际上PhoneApp的代码还没有加载。继续看, 在启动的进程里, 调用
ZygoteInit.zygoteInit
来加载phoneApp的代码:
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.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();
if (descriptors !=
null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr =
System.err;
} catch (ErrnoException ex) {
Log.e(TAG, "
Error reopening stdio"
, ex);
}
}if (parsedArgs.niceName !=
null) {
Process.setArgV0(parsedArgs.niceName);
}// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 这里没有指定invokewith参数
if (parsedArgs.invokeWith !=
null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
// 这里remaingArgs的第一参数是android.app.ActivityThread, 就是之前的entrypoint
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
RuntimeInit.java 通过
RuntimeInit
来加载phone APP的代码, zygoteInit
函数主要做三件事:
- 做一些通用的初始化, 比如设置虚拟机中线程的exception handler; 设置默认时区;
- 完成VM本地的初始化操作;
- 加载APP代码,
也就是调用
ActivityThread.main
函数来加载整个phone APP;
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "
RuntimeInit: Starting application from zygote"
);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "
RuntimeInit"
);
redirectLogStreams();
commonInit();
nativeZygoteInit();
// 初始化应用代码
applicationInit(targetSdkVersion, argv, classLoader);
}
函数
applicationInit
通过方法invokeStaticMain
反射调用ActivityThread.main
:
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks.It is not possible to
// shutdown an Android application gracefully.Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);
// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn'
t needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try {
args =
new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}
// Remaining arguments are passed to the start class'
s static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
invokeStaticMain
通过抛出一个MethodAndArgsCaller
的异常,
被ZygoteInit.main
方法捕获后,
调用MethodAndArgsCaller.run
,
至此就调用了ActivityThread.main
方法了,
还真是有点绕。| 有关zygote进程可以参考http://sniffer.site/2017/05/27/Zygote%E8%BF%9B%E7%A8%8B%E5%90%AF%E5%8A%A8%E8%BF%87%E7%A8%8B%E5%88%86%E6%9E%90/
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
Class<
?>
cl;
try {
cl =
Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"
Missing class when invoking static main "
+
className,
ex);
}Method m;
try {
m =
cl.getMethod("
main"
, new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"
Missing static main on "
+
className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"
Problem getting static main on "
+
className, ex);
}int modifiers =
m.getModifiers();
if (! (Modifier.isStatic(modifiers) &
&
Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"
Main method is not public and static on "
+
className);
}/*
* 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 Zygote.MethodAndArgsCaller(m, argv);
}
MethodAndArgsCaller
异常的作用是清除父进程中的一些调用堆栈,
这样子进程就从ActivityThread.main
开始了自己的堆栈调用。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) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause =
ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
ActivityThread.java 到这里,
ActivityThread.main
会启动一个主线程,
接着创建一个ActivityThread
用于Phone APP与AMS进行交互。最重要的是,
接着在thread.attach(false);
这个函数里,
ActivityThread
会去创建Phone进程入口类PhoneApp
。后续就是Phone整个框架代码的加载与初始化了。
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "
ActivityThreadMain"
);
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);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir =
Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("
<
pre-initialized>
"
);
// 启动主线程Looper
Looper.prepareMainLooper();
ActivityThread thread =
new ActivityThread();
thread.attach(false);
if (sMainThreadHandler =
=
null) {
sMainThreadHandler =
thread.getHandler();
}if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "
ActivityThread"
));
}// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
throw new RuntimeException("
Main thread loop unexpectedly exited"
);
}
【Android Phone进程启动过程详解】这样Phone进程就创建启动完成了。整个流程看下来, 研究Android系统, 源码是王道, 但要深入理解系统背后的设计, 还是需要从把基本的概念梳理清楚, 才能更好的理解系统背后设计的逻辑。
推荐阅读
- android去掉EditView的默认焦点问题
- Android Studio第三十二期 - RecycleView不同布局适配器写法
- C++ STL中的set::erase用法介绍
- 在数组中插入最小值,以使数组总和成为质数
- 条形码和NFC之间有什么区别()
- Linux中的pr命令用法详细介绍
- 算法题(最长回文子串的长度)
- 查找两个字符串中不常见的字符|S2
- C++ STL中的multiset多集cbegin()和cend()函数