Android Context解析

我们今天先来理解Android中Context的设计,很多源码解析的关键流程都会涉及到Context。Context:本意为“上下文”,可以理解为应用当前运行环境提供的一个全局信息接口,具有调用一些应用级别的功能,比如启动Activity、Service,和访问一些应用级别的信息比如Resouce的能力。

我们从一个经典的面试题说开:一个应用中至少有多少个Context? 先来看Context相关类

Context类继承关系

Context本身是个抽象类,具体实现为ContextImpl,其包装类为ContextWrapper,典型的[装饰模式];其关系如下图所示

Android 解读Event和Main Log android context理解_Android

总的来说Context抽象类提供了一系列方法,但是其具体实现均在ContextImpl中,同时提供ContextWrapper,保证了后续拓展上,只需要更改ContextImpl本身即可而不会影响到调用方。通过继承关系我们也可以看出,ApplicationActivityService均继承自ContextWrapper,也就是一个应用中:

Context数目=Application Context + Activity个数 + Service个数。

分析ContextWrapper,可以看到其方法的实现具体都是mBase里面的具体实现。
再看mBase的赋值,是通过attatchBaseContext()赋值。

@android-23 ContextWrapper.java
public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
   	//mBase赋值,传入ContextImpl
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    /**
     * @return the base context as set by the constructor or setBaseContext
     */
    public Context getBaseContext() {
        return mBase;
    }

	//具体方法实现均是分发给mBase对应的实现
    @Override
    public AssetManager getAssets() {
        return mBase.getAssets();
    }

    @Override
    public Resources getResources()
    {
        return mBase.getResources();
    }

    @Override
    public Looper getMainLooper() {
        return mBase.getMainLooper();
    }

那么接下来主要分析两个问题:

  1. Context具有哪些能力
  2. ApplicationActivity、和Service对应的mBase到底是什么时候赋值。

Context 常见方法

以下是Context常见方法调用

public class ContextImpl extends Context {
    private final static String TAG = "ContextImpl";
	//sp cache  
    private static ArrayMap<String, ArrayMap<String, SharedPreferencesImpl>> sSharedPrefs;

	//ActivityThread
    final ActivityThread mMainThread;
	//LoadedApk对象,表征一个已经安装的apk
    final LoadedApk mPackageInfo;

	//用于Binder通信
    private final IBinder mActivityToken;

  	//ContentProvider
    private final ApplicationContentResolver mContentResolver;

	//! 持有mResource,apk资源
    private final ResourcesManager mResourcesManager;
    private final Resources mResources;

	// PackageManager  
    private PackageManager mPackageManager;
   	
	//....
	 @Override
    public AssetManager getAssets() {...}

    @Override
    public Resources getResources() {...}

    @Override
    public PackageManager getPackageManager() {...}

    @Override
    public ContentResolver getContentResolver() {...}

    @Override
    public Looper getMainLooper() {...}

    @Override
    public Context getApplicationContext() {...}

	//...start组件
	@Override
    public void startActivity(Intent intent, Bundle options) {
  		//...
	}

	 @Override
    public void sendBroadcast(Intent intent) {...}

	@Override
    public ComponentName startService(Intent service) {...}

	//...other

可以看到ContextImpl中提供的功能基本分为get全局信息或者接口,提供启动四大组件能力,以及其他的权限检查、文件环境等全局信息的方法。

ContextImpl的初始化

Application对应ContextImpl的初始化

了解Android应用启动流程的同学知道(后续文章会分析),Android应用启动后会在ActivityThread中进行application的初始化,我们来分析相关代码;

@android-23 ActivityThread.java
public static void main(String[] args) {
	....
	//创建主线程Looper
	Looper.prepareMainLooper();
	...
	ActivityThread thread = new ActivityThread();
	//调用 attach
	thread.attatch(false, startSeq) //1

	if(sMainThreadHandler == null) {
		sMainThreadHandler = thread.getHandler();
	}
	...
	Looper.loop();

}

//完成Application的new 以及 ContextImpl的创建
private void attatch(boolean system, long startSeq) {
	...
	try {
		//创建AppContext
		ContextImpl	context = ContextImpl.createAppContext(this, getSystemContext().mPackageInfo);//@2
		mInitialApplication = context.mPackageInfo.makeApplication(...);//@3
		mInitialApplication.onCreate();//@4
	}
}

@2 ContextImpl.java
static ContextImpl createAppContext(ActivityThread mainThread, LoadedApk packageInof) {
	if (packageInof == null) throw new IllegalArgumentException("packageInfo");
	//new ContextImpl
	ContextImpl context = new ContextImpl(null, mainThread, packageInfo, null, null, null, null, 0, null);
	//设置 LoadedApk.mResource
	context.setResources(packageInfo.getResources());//@5
	return context;
}

@3 LoadedApk.java
public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {
	if (mApplication != null) {
		return mApplication;
	}	
	...
	Application app = null;
	String appClass = mApplicationInfo.className;//当前Application类名;
	try {
		java.lang.ClassLoader cl = getClassLoader();
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
		app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext); //@6
		appContext.setOuterContext(app);
	}
	...
	mApplication = app;
}

@6 Instrumentation.java
public Application newAppication(Classloader cl, String className, Context context) throw InstantiationException, IllegalAccessException, ClassNotFoundException {
	Application app = getFactory(context.getPackageName()).instantiateApplication(cl, className); // @7 初始化Application
	app.attach(context);// @8 赋值mBase
	return app;
}

@7 AppComponentFactory.java
public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
    }


@8 Application.java
final void attach(Context context) {
	//attachBaseContext
	attachBaseContext(context);
	...
}

总结:ActivityThread中构造Application的同时创建ContextImpl并且通过attach赋值给对应的mBase

Activity对应ContextImpl初始化分析

我们平时一个典型的用法就是context.startActivity(Intent),分析源码可知启动一个Activity是通过与AMS Binder通信完成的,最终通过Binder通信ActivityThread收到相关调用,通过handleMessage来构造对应Activity来启动,具体分析:

//android-23 @Activity.java
public void startActivityForResource(Intent intent, int requestCode, Bundle options) {
	...
	//调用Instrumentation execStartActivity, Ibinder = applicationThread
	Instrumentation.ActivityResult ar = mInsturementation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this);//@1
}

@Instrumentation.java
public ActivityResult execStartActivity(Context who, IBinder contextThread, IBind token, Activity target, Intent intent, int requestCode, Bundle options) {
	IApplicationThread whoThread = (IApplicationThread)contextThread;
	...
	try {
		int result = ActivityManager.getService().startActivity(...);//Binder调用
			//IActivityManager.startActivity()--Binder onTransation-->AMS
	}
	..
}

@ActivityManagerService.java
public final int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String ......) {
	return startActivityAsUser(...);
}

public final int startActivityAsUser(...) {
...
 return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
                .setCaller(caller)
                .setCallingPackage(callingPackage)
                .setResolvedType(resolvedType)
                .setResultTo(resultTo)
                .setResultWho(resultWho)
                .setRequestCode(requestCode)
                .setStartFlags(startFlags)
                .setProfilerInfo(profilerInfo)
                .setActivityOptions(bOptions)
                .setMayWait(userId)
                .execute();
}

@ActivityStarter.java
int execute() {
	...
	return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
                        mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
                        mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
                        mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
                        mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
                        mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
                        mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
                        mRequest.outActivity, mRequest.inTask, mRequest.reason,
                        mRequest.allowPendingRemoteAnimationRegistryLookup);
}

//这个方法实现比较复杂
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            SafeActivityOptions options,
            boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
            TaskRecord inTask, boolean allowPendingRemoteAnimationRegistryLookup) {
	//进程及uid信息,主要是权限和安全策略
	ProcessRecord callerApp = null;
	if (caller != null) {
		callerApp = mService.getRecordForAppLocked(caller);
		if (callerApp != null) {
			callingPid = callerApp.pid;
			callingUid = callerApp.info.uid;
		}
	}
	...
	//startActivity for result回调功能
	 if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
            // Transfer the result target from the source activity to the new
            // one being started, including any failures.
            if (requestCode >= 0) {
                SafeActivityOptions.abort(options);
                return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
            }
            resultRecord = sourceRecord.resultTo;
            if (resultRecord != null && !resultRecord.isInStackLocked()) {
                resultRecord = null;
            }
            resultWho = sourceRecord.resultWho;
            requestCode = sourceRecord.requestCode;
            sourceRecord.resultTo = null;
            if (resultRecord != null) {
                resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
            }
            if (sourceRecord.launchedFromUid == callingUid) {
                callingPackage = sourceRecord.launchedFromPackage;
            }
        }
	//
}

private int startActivityUnChecked(ActivityRecord r, ActivityRecord sourceRecord, ..int startFlags, ...) {
	//launchMode
	computeLacunchingTaskFlags();
	computeSourceStack();
	mIntent.setFlags(mLaunchFlags);
	//根据不同的launchMode生成对应的mTargetStack
	mTargetStack.startActivityLocked(mStartActivity, ......);
}

@ActivityStack.java
boolean resumeTopActivityUncheckedLocked(AcitivityRecord prev, ActivityOptions options) {
	..
	result = resumeTopActivityInnerLocked(prev, options);
	...
}

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
	...
	mStackSupervison.startSpecificActivityLocked(..);
	...
}

@ActivityStackSuperVisor.java
void startSpecificActivityLocked(...) {
	ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
	//如果应用进程起来
	if(app != null && app.thread != null) {
		...
		realStartActivityLocked(r, app, andResoume, checkConfig);
		return;
	}
	//如果应用进程没起来
	mService.startProcessLocked(...);
}

final boolean realStartActivityLocked() {
	...
	//app.thread = IApplicationThread
	app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),
                    new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,
                    task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,
                    newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);

}

以上是AMS中Activity启动涉及的源码,接下来看看ActivityThread中activity是怎么起来的

@ActivityThread.java
 void scheduleRelaunchActivity(IBinder token) {
        sendMessage(H.RELAUNCH_ACTIVITY, token);
 }

@ActivityThread-H
public void handleMessage(Message msg) {
	...
	case RELAUNCH_ACTIVITY:
                    handleRelaunchActivityLocally((IBinder) msg.obj);
                    break;
	...
}

private void handleRelaunchActivityLocally(IBinder token) {
	 executeTransaction(transaction);
}

@TransactionExecutor.java
public void executre(ClientTransaction transaction) {
	IBinder token = transaction.getActivityToken();
	executeCallbacks(transaction);
	executreLifecycleState(transaction);
}

 public void executeCallbacks(ClientTransaction transaction) {
	 item.execute(mTransactionHandler, token, mPendingActions);//

} 

@AcitivtyRelaunchItem.java 
public void execute(ClientTransactionHandler client, IBinder token..) {
	...
	client,handleRelacunchActivity(mActivityClientRecord, pendingActions);
	...
}

@ActivityThread extends ClientTransactionHandler
 @Override
    public void handleRelaunchActivity(ActivityClientRecord tmp,
            PendingTransactionActions pendingActions) {
	...
	handleRelaunchActivityInner(...);
}

private void handleReLaunchActivityInner() {
	if (!r.paused) {
            performPauseActivity(r, false, reason, null /* pendingActions */);
        }
        if (!r.stopped) {
            callActivityOnStop(r, true /* saveState */, reason);
        }

        handleDestroyActivity(r.token, false, configChanges, true, reason);
	...
	handleLaunchActivity();
}

public Activity handleLaunchActivity(ActivityClientRecord r,
            PendingTransactionActions pendingActions, Intent customIntent) { 
	...
	return performLaunchActivity(...);
}

//这个方法着重分析下
private Activity performLaunchActivity() {
	ActivityInfo info = r.activityInfo;
	if (r.packageInfo == null) {
		r.packageInfo = getPackageInfo(..);
	}

	//拿到对应Component
	 ComponentName component = r.intent.getComponent();
        if (component == null) {
            component = r.intent.resolveActivity(
                mInitialApplication.getPackageManager());
            r.intent.setComponent(component);
        }

        if (r.activityInfo.targetActivity != null) {
            component = new ComponentName(r.activityInfo.packageName,
                    r.activityInfo.targetActivity);
        }

	//创建ContextImpl
	ContextImpl appContext = createBaseContextForActivity(r);
	Activity activity = null;
	//new 出 Activity
	try {
		java.lang.ClassLoader cl = appContext.getClassLoader();
		activity = mInstrumentation.newActivity(cl, component.getClassName, r.intent);
		r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
	}

	//activity attach appContext
	...
	activity.attach(appContext, this, ...);
	...
	//调用activity onCreate
	mInstrumentation,callActivityOnCreate(activity, r.state);
	...
	mActivities.put(r.token, r);
	...
	return activity;
}

//备注:通过考察ActivityRecord类也可以看出在AMS或者系统级别,标志一个Activity的是IBinder token,所以插件化方案修改真实Activity不会导致生命周期异常;
@ContextImpl.java
static ContextImpl createActivityContext(ActivityThread mainThread,
            LoadedApk packageInfo, ActivityInfo activityInfo, IBinder activityToken, int displayId,
            Configuration overrideConfiguration) {
        if (packageInfo == null) throw new IllegalArgumentException("packageInfo");
	...
	//注意与Application对应ContextImpl构造函数的不同
      ContextImpl context = new ContextImpl(null, mainThread, packageInfo, activityInfo.splitName,
                activityToken, null, 0, classLoader);

	context.setResources(..)
     return context;
}

总结:
简单来说,当在Activity中执行startActivity()—->最终调用到mInstrumentation.execStartActivity(),其中它拿着IApplicationThread作为Binder,跟AMS进行通信,然后在AMS中经过ActivityRecord、ActivityStack、ActivityStackSuperVisor等的一顿操作,最终如果这个Activity所在应用进程没起来就去fork进程起Activity,不然直接起Activity,通过IApplicationThread.scheduleLaunchActivity, 发送个消息给H,然后消息处理是在ActivityThreadhandleLaunchActivity,然后在这里通过ContextImpl. createActivityContext创建出ActivityContext,同时通过反射实例化Activity,之后调用对应的attachonCreate方法;

Service对应ContextImpl初始化流程

Servicede的启动流程与Activity类似,所以这次我们不再分析AMS通信过程,还是从ActivityThread入手:

@ActivityThread.java
//通过AMS之后,
 public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
        	//....
            sendMessage(H.CREATE_SERVICE, s);
        }

@H
public void handleMessage(Message msg) {
	 case CREATE_SERVICE:
          handleCreateService((CreateServiceData)msg.obj);
          break;
}

private void handleCreateService(CreateServiceData data) {
         LoadedApk packageInfo = getPackageInfoNoCheck(
                data.info.applicationInfo, data.compatInfo);
        Service service = null;
        try {
            java.lang.ClassLoader cl = packageInfo.getClassLoader();
            service = packageInfo.getAppFactory()
                    .instantiateService(cl, data.info.name, data.intent);
        } 
...
         
	service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();
            mServices.put(data.token, service);
}

总结:
可以看出service的context创建流程与Activity的大同小异,唯一的区别是service的context来自于createAppContext();因为它不需要activity级别的一些属性;

Application、Activity、Service对应Context的区别

默认Application和Service级别的Context是不能用来showDialog的,除非是System Alert类型的。因为可以看出AppContext构造的时候缺少DisplayConfiguration跟应用级别UI显示相关的参数。因此其实启动Activity、Inflater、showDialog都基本上用的是Activity Context。其他具体区别和各自使用场景同学们可以自己研究。