该文章主要讲述了Android系统中Application创建过程的分析,具体涵盖了Application在系统启动时的加载与初始化步骤、进程间通信机制以及相关的内存管理。文章通过深入剖析源码和执行过程,展示了Application创建的核心要点,包括生命周期的管理及与其他系统组件的交互。
1.目录
2.简介
在 Android 应用中,每一个app都对应一个Application对象,Application对象的生命周期等同于app的生命周期。Android可以分为两种应用创建Application对象:system_server进程和app进程。
理解Application的创建过程,有助于理解一代壳的加固原理,一代壳在dex外围新加了一个用于启动的ShellApplication,在启动的过程中,通过ShellApplication代理RealApplication,最终使app的启动顺序、生命周期都回归到RealApplication,同时对getContext,getApplicationContext
函数返回RealApplication的上下文。
3.创建system_server
3.1创建SystemContext
创建system_server的代码位于java\com\android\server\SystemServer.java
的run方法,首先会调用createSystemContext()
创建系统上下文。
private void run() {
...
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
...
}
3.2创建ActivityThread对象
createSystemContext
方法如下,会创建一个ActivityThread对象,ActivityThread 是 Android 应用程序的主线程,负责管理应用程序的生命周期和处理UI操作。
system_server不仅是一个后台进程,其同时运行多个组件的Service进程,与Service进行交互的对话框是由system_server进程提供的,所以system_server也需要一个APK应用的上下文环境。
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
...
}
systemMain方法会调用attach方法,attach方法会创建系统上下文和app上下文。在获取了SystemContext后,通过ContextImpl.createAppContext
方法创建appContext。再调用context.mPackageInfo.makeApplication
创建Application对象。
public static ActivityThread systemMain() {
...
ActivityThread thread = new ActivityThread();
thread.attach(true, 0);
return thread;
}
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
} else {
...
try {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
}
}
其中getSystemContext方法会创建LoadedApk对象,其包名是"android",指向了framework-res.apk。
LoadedApk(ActivityThread activityThread) {
mActivityThread = activityThread;
mApplicationInfo = new ApplicationInfo();
mApplicationInfo.packageName = "android";
...
}
static ContextImpl createSystemContext(ActivityThread mainThread) {
LoadedApk packageInfo = new LoadedApk(mainThread);
ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, 0,
null, null);
context.setResources(packageInfo.getResources());
context.mResources.updateConfiguration(context.mResourcesManager.getConfiguration(),
context.mResourcesManager.getDisplayMetrics());
return context;
}
3.3 创建Application对象
首先判断mApplication对象是否是null,不是则表明application已经生成了。否则,调用mActivityThread.mInstrumentation.newApplication
创建application。
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
return mApplication;
}
Application app = null;
String appClass = mApplicationInfo.className;
if (forceDefaultAppClass || (appClass == null)) {
appClass = "android.app.Application";
}
try {
java.lang.ClassLoader cl = getClassLoader();
...
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
}
...
mActivityThread.mAllApplications.add(app);
mApplication = app;
if (instrumentation != null) {
try {
instrumentation.callApplicationOnCreate(app);
}...
}
return app;
}
跟入newApplication
方法,发现在创建application时会调用app的attach方法,跟进后发现调用的是attachBaseContext
。所以该方法优先于onCreate
方法执行。
public Application newApplication(ClassLoader cl, String className, Context context) {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
return app;
}
/* package */ final void attach(Context context) {
attachBaseContext(context);
mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}
4.创建用户级的application流程
与创建system_server相似,创建用户级的application通过ActivityThread.main
方法,此时attach进入if逻辑,然后通过AMS(ActivityManagerService)进行创建。
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
mgr.attachApplication(mAppThread, startSeq);
AMS调用ActivityThread.bindApplication
方法,通过Binder发送BIND_APPLICATION
消息调用ActivityThread创建application。
public final void attachApplication(IApplicationThread thread, long startSeq) {
...
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);
Binder.restoreCallingIdentity(origId);
}
}
private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
int pid, int callingUid, long startSeq) {
...
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.isPersistent(),
new Configuration(app.getWindowProcessController().getConfiguration()),
app.compat, getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, autofillOptions, contentCaptureOptions);
}
public final void bindApplication(...){
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
...
sendMessage(H.BIND_APPLICATION, data);
...
}
具体创建函数是handleBindApplication
,后面的流程则和system_server进程一致。
public void handleMessage(Message msg) {
switch (msg.what) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
}
private void handleBindApplication(AppBindData data) {
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
...
app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
...
try {
mInstrumentation.callApplicationOnCreate(app);
}
5.加壳思路
首先需要理清楚用户的Application创建过程,如图5-1所示。根据途中app的创建过程,ShellApplication同样可以调用makeApplication创建RealApplication。
-
修改AndroidManifest.xml,将ShellApplication作为MainApplication。
-
系统创建ShellApplication时,在attachBaseContext方法中动手。
-
由于makeApplication需要满足以下条件,才会创建RealApplication,即mApplication=null,且mApplicationInfo.className由我们控制。
public final class LoadedApk { private ApplicationInfo mApplicationInfo; private Application mApplication; ... if (mApplication != null) { return mApplication; } Application app = null; String appClass = mApplicationInfo.className; if (forceDefaultAppClass || (appClass == null)) { appClass = "android.app.Application"; } ... }
-
为了满足3的要求,首先看到ActivityThread类的关键成员属性,其中mBoundApplication类型是AppBindData,而其成员属性包含了LoadedApk,ApplicationInfo,providers。
public final class ActivityThread extends ClientTransactionHandler { AppBindData mBoundApplication; Application mInitialApplication; final ArrayList<Application> mAllApplications = new ArrayList<Application>(); } static final class AppBindData { @UnsupportedAppUsage LoadedApk info; @UnsupportedAppUsage String processName; @UnsupportedAppUsage ApplicationInfo appInfo; @UnsupportedAppUsage List<ProviderInfo> providers; }
-
反射获取ActivityThread对象,进而得到LoadedApk对象、AppBindData对象、ApplicationInfo对象。
-
修改LoadedApk.mApplication=null。
-
修改AppBindData.appInfo.className和LoadedApk.mApplicationInfo.className为RealApplication的类名。
-
修改mAllApplications,将ShellApplication从中移除。
-
反射调用makeApplication方法,生成RealApplication。
此时对于
Context.getContext
和Context.getApplicationContext
方法返回的都是RealApp的上下文。但ContentProvider
中也有getContext
,如下文所示,mContext有两处可以赋值,分别是构造方法和attachInfo
方法。根据图5-1,attachInfo是通过ActivityThread.installProvider方法的
localProvider.attachInfo(c, info);
调用,而installProvider的context参数则是由handleBindApplication传入,即context=app。同时根据图5-1,ContentPrivider的初始化是在attachBaseContext之后的,此时看到installProvider类,如果控制了ActivityThread.mInitialApplication的值为RealApplication并且绕过第一个if条件,但仍然会被handleBindApplication覆盖为ShellApplication。
- 但可以注意到
data.providers is empty
,则可以避免系统自动创建ContentProvider,此时则将data.providers
置空,由attachBaseContext手动创建ContentProvider。 - 在Application.onCreate中恢复data.providers。
private void handleBindApplication(AppBindData data) { data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo); final ContextImpl appContext = ContextImpl.createAppContext(this, data.info); ... app = data.info.makeApplication(data.restrictedBackupMode, null); mInitialApplication = app; if (!data.restrictedBackupMode) { if (!ArrayUtils.isEmpty(data.providers)) { installContentProviders(app, data.providers); } } ... try { mInstrumentation.callApplicationOnCreate(app); }
private ContentProviderHolder installProvider(Context context, ContentProviderHolder holder, ProviderInfo info, boolean noisy, boolean noReleaseNeeded, boolean stable) { Context c = null; ApplicationInfo ai = info.applicationInfo; if (context.getPackageName().equals(ai.packageName)) { c = context; } else if (mInitialApplication != null && mInitialApplication.getPackageName().equals(ai.packageName)) { c = mInitialApplication; } else { try { c = context.createPackageContext(ai.packageName, Context.CONTEXT_INCLUDE_CODE); } catch (PackageManager.NameNotFoundException e) { // Ignore } } localProvider.attachInfo(c, info); }
public abstract class ContentProvider implements ContentInterface, ComponentCallbacks2 { private Context mContext = null; public ContentProvider( Context context, String readPermission, String writePermission, PathPermission[] pathPermissions) { mContext = context; mReadPermission = readPermission; mWritePermission = writePermission; mPathPermissions = pathPermissions; } public final @Nullable Context getContext() { return mContext; } private void attachInfo(Context context, ...) { if (mContext == null) { mContext = context; } }
-
图5-1
Comments NOTHING