本篇源码分析基于Android8.0 API 26
关于Android源码查看:
你可以去看这里:https://android.googlesource.com/platform/frameworks/base/ 在线查看,也可以在Android Studio里面关联源码,也可以完全下载自己去编译
前言
其实app启动就是调用了一个startActivity,但是这个startActivity方法并没有我们想像中的那么简单,这其中牵涉到了三个进程:Zygote进程,system_server进程,还有被启动的app进程,其中还牵涉到Binder通信,AIDL,Handler机制等等,如果你把这几位搞明白再去看App启动源码,也许理解的更快一些,假如这几位你不是很理解,也是可以看app启动流程的,没准你会对他们更加感兴趣。
1,桌面图标点击
当我们点击Android系统桌面的应用图标的时候,app被启动,然后进入我们的MainActivity,呈现到用户面前,这就是App被启动了。其实桌面也只不过是一个app,它的名字叫Launcher,只不过是系统把它启动起来的,这里不关心Launcher的启动流程,只关心它里面的图标点击事件。
这里需要去看Launcher的源码,感兴趣的可以去看这里 https://android.googlesource.com/platform/packages/apps/
Launcher中的App列表使用的RecyclerView
//public class AllAppsRecyclerView extends BaseRecyclerView//public abstract class BaseRecyclerView extends RecyclerView//AllAppsRecyclerView最终继承自RecyclerView <com.android.launcher3.allapps.AllAppsRecyclerView android:id="@+id/apps_list_view" android:layout_below="@id/search_container_all_apps" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center_horizontal|top" android:clipToPadding="false" android:overScrollMode="never" android:descendantFocusability="afterDescendants" android:focusable="true" />
这个Activity叫做Launcher.java,既然是RecyclerView,我们很自然的想到了item点击事件,item点击事件其实是对item设置的View.OnClickListener事件,恰巧Launcher实现了这个事件
/**
* Default launcher application.
*/public class Launcher extends BaseActivity
implements LauncherExterns, View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener, AccessibilityManager.AccessibilityStateChangeListener, WallpaperColorInfo.OnThemeChangeListener {那么是不是这里就是用来处理RecyclerView应用图标的点击事件呢?答案是yes
给AllAppsRecyclerView设置adapter被封装到了AllAppsContainerView里面,然后AllAppsContainerView里面
mAdapter = new AllAppsGridAdapter(mLauncher, mApps, mLauncher, this);
AllAppsGridAdapter
/**
* The grid view adapter of all the apps.
*/
public class AllAppsGridAdapter extends RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> { ...
//AllAppsGridAdapter构造函数传入iconClickListener
public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
iconClickListener, View.OnLongClickListener iconLongClickListener) {
Resources res = launcher.getResources();
mLauncher = launcher;
mApps = apps;
mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
mGridSizer = new GridSpanSizer();
mGridLayoutMgr = new AppsGridLayoutManager(launcher);
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mLayoutInflater = LayoutInflater.from(launcher);
mIconClickListener = iconClickListener;
mIconLongClickListener = iconLongClickListener; if (FeatureFlags.LAUNCHER3_PHYSICS) {
mSpringAnimationHandler = new SpringAnimationHandler<>(
SpringAnimationHandler.Y_DIRECTION, new AllAppsSpringAnimationFactory());
}
} ...
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) {
case VIEW_TYPE_ICON:
case VIEW_TYPE_PREDICTION_ICON:
//icon点击事件
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.all_apps_icon, parent, false);
icon.setOnClickListener(mIconClickListener);
icon.setOnLongClickListener(mIconLongClickListener);
icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
icon.setOnFocusChangeListener(mIconFocusListener);
// Ensure the all apps icon height matches the workspace icons in portrait mode.
icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx; return new ViewHolder(icon); ...
}
} ...}可见这个点击事件被设置上了,现在我们回去看看Launcher.java这个Activity里面的onClick事件
/**
* Launches the intent referred by the clicked shortcut.
*
* @param v The view representing the clicked shortcut.
*/public void onClick(View v) {
...
Object tag = v.getTag(); if (tag instanceof ShortcutInfo) {
onClickAppShortcut(v);
} else if (tag instanceof FolderInfo) { if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if ((v instanceof PageIndicator) ||
(v == mAllAppsButton && mAllAppsButton != null)) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) { //执行这里
startAppShortcutOrInfoActivity(v);
} else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v);
}
}
}//拿到应用信息,执行startActivitySafely(v, intent, item)private void startAppShortcutOrInfoActivity(View v) {
ItemInfo item = (ItemInfo) v.getTag();
Intent intent; if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
intent = promiseAppInfo.getMarketIntent();
} else {
intent = item.getIntent();
} if (intent == null) { throw new IllegalArgumentException("Input must have a valid intent");
} boolean success = startActivitySafely(v, intent, item);
getUserEventDispatcher().logAppLaunch(v, intent); // TODO for discovered apps b/35802115
if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
}public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
... // Only launch using the new animation if the shortcut has not opted out (this is a
// private contract between launcher and may be ignored in the future).
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
Bundle optsBundle = useLaunchAnimation ? getActivityLaunchOptions(v) : null;
UserHandle user = item == null ? null : item.user; // Prepare intent
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (v != null) {
intent.setSourceBounds(getViewBounds(v));
} try { if (Utilities.ATLEAST_MARSHMALLOW
&& (item instanceof ShortcutInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((ShortcutInfo) item).isPromise()) { // Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) { // Could be launching some bookkeeping activity
startActivity(intent, optsBundle);
} else {
LauncherAppsCompat.getInstance(this).startActivityForProfile(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
} return true;
} catch (ActivityNotFoundException|SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
} return false;
}可以看到最后执行的是startActivity方法,startActivity是Activity的方法,关于app图标点击事件先讲到这。
app启动
从上面桌面的图标点击事件,来到了Activity中的startActivity方法,这里第二个参数 Bundle options我也不知道是空还是非空,但是,没关系,他们最终执行的是startActivityForResult方法
/**
* @param intent The intent to start.
* @param options 给Activity的启动设置一些额外的属性
* See {@link android.content.Context#startActivity(Intent, Bundle)}
* Context.startActivity(Intent, Bundle)} for more details.
*/@Overridepublic void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) {
startActivityForResult(intent, -1, options);
} else { // Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) { if (mParent == null) {
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options); if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
} if (requestCode >= 0) { // If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options); // TODO Consider clearing/flushing other event sources and events for child windows.
} else { if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
} else { // Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}startActivityForResult方法先判断if (mParent == null),这里的mParent是指的Activity的父Activity,一般的Activity中mParent都是空的。所以执行的是往下执行的是execStartActivity方法,注意到这里execStartActivity的第二个参数传入的是mMainThread.getApplicationThread(),mMainThread是ActivityThread,mMainThread.getApplicationThread()获取的是ApplicationThread,这两个东西都很重要,后面回讲到。继续往下看
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null; if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
} if (mActivityMonitors != null) { synchronized (mSync) { final int N = mActivityMonitors.size(); for (int i=0; i<N; i++) { final ActivityMonitor am = mActivityMonitors.get(i);
ActivityResult result = null; if (am.ignoreMatchingSpecificIntents()) {
result = am.onStartActivity(intent);
} if (result != null) {
am.mHits++; return result;
} else if (am.match(who, null, intent)) {
am.mHits++; if (am.isBlocking()) { return requestCode >= 0 ? am.getResult() : null;
} break;
}
}
}
} try {
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess(who); int result = ActivityManager.getService()
.startActivity(whoThread, who.getBasePackageName(), intent,
intent.resolveTypeIfNeeded(who.getContentResolver()),
token, target != null ? target.mEmbeddedID : null,
requestCode, 0, null, options);
checkStartActivityResult(result, intent);
} catch (RemoteException e) { throw new RuntimeException("Failure from system", e);
} return null;
}你如果在网上看以前别人的源码ActivityManager.getService().startActivity这个位置是ActivityManagerNative.getDefault().startActivity,在Android API26以后源码发生了改变,不使用以前的那种形式了。不过不影响,原理都是相通的。ActivityManager.getService()拿到的是IActivityManager,IActivityManager是一个aidl文件,现在用到aidl了。ActivityManagerService圈内简称AMS,是一个很重要的系统服务类,存在于system_server进程,ActivityManagerService继承自IActivityManager.Stub,所以上面ActivityManager.getService().startActivity调用的其实是ActivityManagerService里面的方法
/**
* @hide
*/public static IActivityManager getService() { return IActivityManagerSingleton.get();
}public class ActivityManagerService extends IActivityManager.Stub
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {根据参数对号入座
@Overridepublic final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) { return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}@Overridepublic final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
enforceNotIsolatedCaller("startActivity");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null); // TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, null, "startActivityAsUser");
}下面就是各种调用,我翻过一道道山川,却迷失在你的芦苇荡。这里面有非常多的调用,注意不要跟丢
ActivityStarter.java -->startActivityMayWait-->startActivityLocked-->startActivity-->startActivity-->startActivityUncheckedActivityStackSupervisor.java -->resumeFocusedStackTopActivityLockedActivityStack.java -->resumeTopActivityUncheckedLocked-->resumeTopActivityInnerLockedActivityStackSupervisor.java -->startSpecificActivityLocked
下面看一下startSpecificActivityLocked这个方法,ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid, true);拿到这个app进程纪录。先判断这个进程是不是已经启动过,假如启动过执行realStartActivityLocked,假如没有启动过,执行 mService.startProcessLocked启动新的进程。
void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running?
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r); if (app != null && app.thread != null) { //假如app进程已经在运行,直接去启动
try { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
|| !"android".equals(r.info.packageName)) { // Don't add this if it is a platform component that is marked
// to run in multiple processes, because this is actually
// part of the framework so doesn't make sense to track as a
// separate apk in the process.
app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
mService.mProcessStats);
}
realStartActivityLocked(r, app, andResume, checkConfig); return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
} // If a dead object exception was thrown -- fall through to
// restart the application.
} //否则开进程启动
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true);
}由于代码太多,关于app应用启动流程分为两篇,第一篇先到这里,下一篇,接着这一篇,分开讲讲
进程已经启动过,并且还存在没被杀死,那么去打开Activity.
进程不存在,启动新的进程。
共同学习,写下你的评论
评论加载中...
作者其他优质文章