Activity
参见这篇博客
题外话:桥接模式
在Activity的设计中用到了桥接模式,利用这个模式达到了对修改封闭,对扩展开放的目的。
在对Activity的创建过程进行分析时发现,在创建一个Activity后都会对其绑定一个ContextImpl实例。查看源码后发现,这个contextImpl实例是以context的形式作为成员变量被保存在activity(ContextWrapper)中。
Context mBase;
这里的mBase其实相当于一座桥,Activity的许多操作例如getSystemService,都是通过mBase来调用的,而Context只是一个接口,这里就给Context的扩展留下机会。它可以是Context的任意子类。
以这样的方式来提升系统的扩展性是非常不错的选择。
Service
由于篇幅原因,关于Service的启动过程分析放在这里。
BoradCastReceiver
上面分析了Activity和Service的相关过程,广播作为四大组件之一,注册,发送广播过程其实和上面两个组件也都基本相同。由于静态广播由PMS(PackageManagerService)统一注册,这里暂不分析。下面来看一看动态广播的注册和发送过程。
注册过程同样由ContextImpl真正去执行。
private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
IntentFilter filter, String broadcastPermission,
Handler scheduler, Context context, int flags) {
IIntentReceiver rd = null;//这里类比Service的IServiceConnection
if (receiver != null) {
if (mPackageInfo != null && context != null) {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = mPackageInfo.getReceiverDispatcher(//这里类比Service启动中的ServiceDispatcher
receiver, context, scheduler,
mMainThread.getInstrumentation(), true);
} else {
if (scheduler == null) {
scheduler = mMainThread.getHandler();
}
rd = new LoadedApk.ReceiverDispatcher(
receiver, context, scheduler, null, true).getIIntentReceiver();
}
}
try {
//由AMS真正去注册
final Intent intent = ActivityManager.getService().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
broadcastPermission, userId, flags);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
}
return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到注册过程和Service的启动过程极为类似。由于广播也可能运行在独立线程,因此广播的回调要以binder的方式来传给AMS。
在AMS中这个回调和对应的filter会被保存起来,当发送广播时,同样是ContextImpl来跨进程调用AMS的发送广播方法。这时AMS会遍历广播回调,如果有对应的应用进程存在,那么就把广播就给app去处理,否则直接调用广播回调的相关方法。
void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {//app对应的进程
if (app.thread != null) {//对applicationThread的判断
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
try {
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
// TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
// DeadObjectException when the process isn't actually dead.
//} catch (DeadObjectException ex) {
// Failed to call into the process. It's dying so just let it die and move on.
// throw ex;
} catch (RemoteException ex) {
// Failed to call into the process. It's either dying or wedged. Kill it gently.
synchronized (mService) {
Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+ " (pid " + app.pid + "). Crashing it.");
app.scheduleCrash("can't deliver broadcast");
}
throw ex;
}
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {//否则直接跨进程调用
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}
ApplicationThread中同样会调用receiver.performReceive方法。我对这里的理解是,如果activity发送了一个广播,那么AMS负责把这个广播对应的Reciver交给activity,如果找不到activity,则直接调用onReceive方法。就算是activity去处理Receiver,广播和activity也可能不在一个进程。这里可以自己体会一下。
广播对应的基本流程就是这样。还有一个要注意的地方。在Android3.1之后,发送广播时会有这么一段:
final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
intent = new Intent(intent);
......
// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
......
}
就是说会给intent自动添加一个不给已经停止的应用发广播的标记。这里的停止指的是安装后从未启动和被用户手动杀死的应用。如果确实要给已经停止的应用发广播,那么则要手动加上:
Intent.FLAT_INCLUDE_STOPPED_PACKAGES
两种标记位共存时,会取后者。
ContentProvider
ContentProvider的启动过程和其他组件略有不同。要了解ContentProvider的启动过程,可以先看一下Application的创建过程。
Application的创建要从应用程序入口说起。
ActivityThread的入口是main方法。在这个方法中初始化了主线程handler,并且创建了ActivityThread对象,调用了其attach方法。
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
......
final IActivityManager mgr = ActivityManager.getService();//获取AMS的binder client
try {
mgr.attachApplication(mAppThread);//调用AMS的attachApplication方法
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
......
}
......
}
可以看到获取AMS和调用attachApplication方法。
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
......
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
......
if (app.instr != null) {
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial);
}
}
可以看到这里会尝试从AMS中获取Provider,其中generateApplicationProvidersLocked方法大概就是去PackageManager里面找所有声明过的Provider。
然后AMD中调用了thread的bindApplication方法。这里的thread就是ApplicationThread。是ActivityThread和AMS通信的binder。
bindApplication中向主线程handler发送了一个消息,最终会调用handleBindApplication方法。
private void handleBindApplication(AppBindData data) {
......
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs);
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
......
}
这个方法很长,我们主要关注这几行。首先是创建Application对象,这个过程在makeApplication中进行。同时被创建的还有ApplicationContext。然后会对data.providers进行判空,也就是AMS传过来的providers。如果有数据,则进行初始化:
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
......
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
ContentProvider对象的创建是在installProvider中。接着创建的ContentProvider都会保存在AMS中,方便别的进程调用。
值得注意的是,ContentProvider的创建是在Application的onCreate方法之前,有兴趣的同学可以回到初始化Application的代码处,你会发现在创建了Application后并没有立刻执行其onCreate方法,而是在创建完ContentProvider之后由mInstrumentation来调用其onCreate方法。
当我们在Activity中调用getContentResolver的acquireContentProviderClient方法时,ContextImpl会去ActivityThread中查找有没有本地保存的ContentProvider。如果有就返回,如果没有就去找AMS要。AMS会检查它的mProviderMap(ContentProvider在创建后会回调给AMS,就保存在这个mProviderMap中),如果有就返回,如果发现其所在进程没有启动,则会先启动对应进程。