前言
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情
我们的app启动流程的开始是从点击桌面的图标开始的,那么Launcher进程是如何通过进程间的通信启动我们的app的,今天我们就来聊一聊这中间经历了什么.
一、Launcher概述
1.1 Launcher.Activity
其实Launcher本质上也是一个APP,当点击桌面图标时,App就启动了
/packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
public final class Launcher extends Activity
implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
View.OnTouchListener {
可以看到Launcher和普通的app一样,也是继承自Activity.那就看一下它的布局文件.
@Override
protected void onCreate(Bundle savedInstanceState) {
...
setContentView(R.layout.launcher);
...
}
1.2 launcher.xml
/packages/apps/Launcher2/res/layout-land/launcher.xml
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2007 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Full screen view projects under the status bar and contains the background -->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:id="@+id/launcher"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/workspace_bg">
<com.android.launcher2.DragLayer
android:id="@+id/drag_layer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- The workspace contains 5 screens of cells -->
//WorkSpace即存放手机图标的桌面,默认系统是包含可翻转5页,其中launcher:defaultScreen="2"
//这句话默认有两个菜单界面,一个存放所有已安装的应用程序图标,另一个存放小部件.
<com.android.launcher2.Workspace
android:id="@+id/workspace"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingStart="@dimen/workspace_left_padding"
android:paddingEnd="@dimen/workspace_right_padding"
android:paddingTop="@dimen/workspace_top_padding"
android:paddingBottom="@dimen/workspace_bottom_padding"
launcher:defaultScreen="2"
launcher:cellCountX="@integer/cell_count_x"
launcher:cellCountY="@integer/cell_count_y"
launcher:pageSpacing="@dimen/workspace_page_spacing"
launcher:scrollIndicatorPaddingLeft="@dimen/qsb_bar_height"
launcher:scrollIndicatorPaddingRight="@dimen/button_bar_height">
//Workspace总共可翻转5个页面,一个workspace_screen定义一个页面布局
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
<include android:id="@+id/cell2" layout="@layout/workspace_screen" />
<include android:id="@+id/cell3" layout="@layout/workspace_screen" />
<include android:id="@+id/cell4" layout="@layout/workspace_screen" />
<include android:id="@+id/cell5" layout="@layout/workspace_screen" />
</com.android.launcher2.Workspace>
//dock_divider为左桌面分隔线,将hotseat和Workspace分隔,注意这是横屏的源码.
//所以出现了左分隔线和右分隔线,如果是竖屏时的源码(应当是上下分割线)
<include
android:id="@+id/qsb_divider"
layout="@layout/workspace_divider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="@dimen/qsb_bar_height"
android:layout_gravity="start" />
//dock_divider为右边桌面分隔线,将hotseat和Workspace分隔
<include
android:id="@+id/dock_divider"
layout="@layout/workspace_divider"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginEnd="@dimen/button_bar_height"
android:layout_gravity="end" />
//桌面分割线的上指示器,Workspace翻页的时候显示
<include
android:id="@+id/paged_view_indicator"
layout="@layout/scroll_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom" />
//hotseat为桌面分隔线下的界面,不随Workspace翻页操作而移动
<include layout="@layout/hotseat"
android:id="@+id/hotseat"
android:layout_width="@dimen/button_bar_height_plus_padding"
android:layout_height="match_parent"
android:layout_gravity="end" />
//qsb_bar布局包含桌面上的可搜索框 以及长按桌面上图标时显示删除和应用信息的操作框.
<include
android:id="@+id/qsb_bar"
layout="@layout/qsb_bar" />
//手机刚开机,或者对launcher应用清空数据第一次进入到workspace时弹出的操作介绍界面.
<!-- The Workspace cling must appear under the AppsCustomizePagedView below to ensure
that it is still visible during the transition to AllApps and doesn't overlay on
top of that view. -->
<include layout="@layout/workspace_cling"
android:id="@+id/workspace_cling"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
//手机刚开机,或者对launcher应用清空数据,第一次打开将workspace上两个以上的图标拖到一起形成的文件夹时弹出的操作界面
<include layout="@layout/folder_cling"
android:id="@+id/folder_cling"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" />
<com.android.launcher2.DrawableStateProxyView
android:id="@+id/voice_button_proxy"
android:layout_width="@dimen/qsb_bar_height"
android:layout_height="@dimen/app_icon_size"
android:layout_gravity="top|start"
android:layout_marginTop="64dp"
android:clickable="true"
android:onClick="onClickVoiceButton"
android:importantForAccessibility="no"
launcher:sourceViewId="@+id/voice_button" />
//点击hotseat中心图标进入的界面,该界面显示所有应用和小部件
<include layout="@layout/apps_customize_pane"
android:id="@+id/apps_customize_pane"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="invisible" />
</com.android.launcher2.DragLayer>
</FrameLayout>
可以看到 Launcher的桌面布局(从上到下位搜索框qsb_bar,Workspace,分割线dock_divider,hotseat)
apps_customize_pane显示所有已安装的应用程序和已创建的widget(小部件)
1.3 Workspace
下面我们重点来看下xml中的Workspace布局
public class Workspace extends SmoothPagedView
implements DropTarget, DragSource, DragScroller, View.OnTouchListener,
DragController.DragListener, LauncherTransitionable, ViewGroup.OnHierarchyChangeListener {
...
}
public abstract class SmoothPagedView extends PagedView {
...
}
public abstract class PagedView extends ViewGroup implements ViewGroup.OnHierarchyChangeListener {
}
可以看到,这个自定义的View,Workspace继承自SmoothPagedView,SmoothPagedView又继承自PagedView,PagedView再继承自ViewGroup
这个Workspace也是我们平常用来点击app启动别的应用程序的主要入口.
1.4 CellLayout
在这个ViewGroup中,include了五个标签
<include android:id="@+id/cell1" layout="@layout/workspace_screen" />
分别包含了5个id位cell1,cell2,cell3,cell4,cell5的子视图,可以有多个存放图片的子页面,类似于ViewPager中的Fragment,它们对应的布局为 workspace_screen.xml
<com.android.launcher2.CellLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res/com.android.launcher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="@dimen/cell_layout_left_padding"
android:paddingEnd="@dimen/cell_layout_right_padding"
android:paddingTop="@dimen/cell_layout_top_padding"
android:paddingBottom="@dimen/cell_layout_bottom_padding"
android:hapticFeedbackEnabled="false"
launcher:cellWidth="@dimen/workspace_cell_width"
launcher:cellHeight="@dimen/workspace_cell_height"
launcher:widthGap="@dimen/workspace_width_gap"
launcher:heightGap="@dimen/workspace_height_gap"
launcher:maxGap="@dimen/workspace_max_gap" />
可以看到,这里workspace_screen的布局文件就是一个cellLayout
public class CellLayout extends ViewGroup {
private BubbleTextView mPressedOrFocusedIcon;
private ShortcutAndWidgetContainer mShortcutsAndWidgets;
...
}
CellLayout也是继承自ViewGroup的,而我们今天需要重点关注的是里面的ShortcutAndWidgetContainer和BubbleTextView
1.5 ShortcutAndWidgetContainer
public class ShortcutAndWidgetContainer extends ViewGroup {
...
}
正如它的英文名字直译过来一样,他是一个用来放置快捷图标和Widget小部件的View
二、 BubbleTextView
/**
* TextView that draws a bubble behind the text. We cannot use a LineBackgroundSpan
* because we want to make the bubble taller than the text and TextView's clip is
* too aggressive.
*/
public class BubbleTextView extends TextView {
...
public void applyFromShortcutInfo(ShortcutInfo info, IconCache iconCache) {
Bitmap b = info.getIcon(iconCache);
setCompoundDrawablesWithIntrinsicBounds(null,
new FastBitmapDrawable(b),
null, null);
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.contentDescription);
}
setTag(info);
}
...
}
首先可以看到BubbleTextView继承了TextView的一个类,是有TextView的基本属性的--可以设置文本
再看下它的注释:TextView是在文本后面绘制一个气泡,我们不能使用LineBackgroundSpan,因为我们想让气泡比文本更高,TextView的剪辑太激进了.
也就是说,TextView的气泡可以追加在文本后面,但是现在需要把这个气泡移到文本上面
2.1 applyFromShortcutInfo
在这个方法中,我们可以看到它获得了Icon,又进行了一些设置
setCompoundDrawablesWithIntrinsicBounds(null,
new FastBitmapDrawable(b),
null, null);
根据注释以及方法名,我们大致能猜出来,这个BubbleTextView就是桌面上的小图标
2.2 点击图标
OK,到这一步,已经找到了桌面的图标,下一步就是点击启动它了.找一下applyFromShortcutInfo方法.
三、Launcher
3.1 createShortcut
/packages/apps/Launcher2/src/com/android/launcher2/Launcher.java
View createShortcut(int layoutResId, ViewGroup parent, ShortcutInfo info) {
BubbleTextView favorite = (BubbleTextView) mInflater.inflate(layoutResId, parent, false);
//给BubbleTextView设置相应App的Icon
favorite.applyFromShortcutInfo(info, mIconCache);
//给BubbleTextView设置点击事件
favorite.setOnClickListener(this);
return favorite;
}
3.2 onClick
/**
* Launches the intent referred by the clicked shortcut.
*
* @param v The view representing the clicked shortcut.
*/
public void onClick(View v) {
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
if (v.getWindowToken() == null) {
return;
}
if (!mWorkspace.isFinishedSwitchingState()) {
return;
}
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
// Open shortcut
final Intent intent = ((ShortcutInfo) tag).intent;
int[] pos = new int[2];
v.getLocationOnScreen(pos);
intent.setSourceBounds(new Rect(pos[0], pos[1],
pos[0] + v.getWidth(), pos[1] + v.getHeight()));
boolean success = startActivitySafely(v, intent, tag);
if (success && v instanceof BubbleTextView) {
mWaitingForResume = (BubbleTextView) v;
mWaitingForResume.setStayPressed(true);
}
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) v;
handleFolderClick(fi);
}
} else if (v == mAllAppsButton) {
if (isAllAppsVisible()) {
showWorkspace(true);
} else {
onClickAllAppsButton(v);
}
}
}
可以看到在Launcher中我们终于实现了BubbleTextView的onClick方法,然后在这个方法中调用了startActivitySafely(v, intent, tag);方法
3.3 startActivitySafely
boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
try {
success = startActivity(v, intent, tag);
} catch (ActivityNotFoundException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Unable to launch. tag=" + tag + " intent=" + intent, e);
}
return success;
}
这里调用了startActivitySafely
3.4 startActivity
boolean startActivity(View v, Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
// 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);
UserHandle user = (UserHandle) intent.getParcelableExtra(ApplicationInfo.EXTRA_PROFILE);
LauncherApps launcherApps = (LauncherApps)
this.getSystemService(Context.LAUNCHER_APPS_SERVICE);
if (useLaunchAnimation) {
ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(v, 0, 0,
v.getMeasuredWidth(), v.getMeasuredHeight());
if (user == null || user.equals(android.os.Process.myUserHandle())) {
// Could be launching some bookkeeping activity
startActivity(intent, opts.toBundle());
} else {
launcherApps.startMainActivity(intent.getComponent(), user,
intent.getSourceBounds(),
opts.toBundle());
}
} else {
if (user == null || user.equals(android.os.Process.myUserHandle())) {
startActivity(intent);
} else {
launcherApps.startMainActivity(intent.getComponent(), user,
intent.getSourceBounds(), null);
}
}
return true;
} catch (SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
Log.e(TAG, "Launcher does not have the permission to launch " + intent +
". Make sure to create a MAIN intent-filter for the corresponding activity " +
"or use the exported attribute for this activity. "
+ "tag="+ tag + " intent=" + intent, e);
}
return false;
}
3.5 startActivity(intent, opts.toBundle());
到这里就是我们熟悉的Activity.startActivity(intent, opts.toBundle());
由于在开头设置了
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
所以这个Activity会被添加到一个新的Task栈中.
四、Activity
4.1 startActivity(intent, opts.toBundle());
/frameworks/base/core/java/android/app/Activity.java
@Override
public 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);
}
}
4.2 startActivityForResult
其实还是调用了startActivityForResult方法
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
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);
}
}
}
注意这里出现了一个新的东西:Instrumentation.每个Activity都持有一个Instrumentation对象的引用.但是整个进程只会存在一个Instrumentation对象
当调用startActivityForResult方法后,实际上调用了 mInstrumentation.execStartActivity
五、Instrumentation
Instrumentation翻译过来是仪器的意思,这个类里面的方法大多数和Application和Activity有关.准确地说,这个类就是完成对Application和Activity的初始化和生命周期的调控
5.1 execStartActivity
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);
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 = ActivityManagerNative.getDefault()
.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;
}
我们看一下入参
- IBinder---mMainThread.getApplicationThread()
另外注意一下result
int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options);
六、ActivityManagerNative
6.1 getDefault
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
gDefault通过单例模式获取,并且这个对象通过asInterface(b)获得.
6.2 asInterface
//最终返回的是一个ActivityManagerProxy对象
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
//这里面的Binder类型的obj参数会作为ActivityManagerProxy的成员变量保存为mRemote成员变量,负责进行IPC通信.
return new ActivityManagerProxy(obj);
}
可以看到,这个IBinder对象是通过ServiceManager.getService("activity");方法产生的.而execStartActivity()中的ActivityManagerNative.getDefault()返回的实际上就是通过单例模式返回的一个ActivityManagerProxy对象
七、ActivityManagerProxy
7.1 startActivity
/frameworks/base/core/java/android/app/ActivityManagerNative.java
class ActivityManagerProxy implements IActivityManager
{
public ActivityManagerProxy(IBinder remote)
{
mRemote = remote;
}
public IBinder asBinder()
{
return mRemote;
}
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(callingPackage);
intent.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(resultTo);
data.writeString(resultWho);
data.writeInt(requestCode);
data.writeInt(startFlags);
if (profilerInfo != null) {
data.writeInt(1);
profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} else {
data.writeInt(0);
}
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
return result;
}
...
}
这里的startActivity()方法就是前面我们重要的两句代码
int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target, requestCode, 0, null, options);
7.2 参数
public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,
String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags,
ProfilerInfo profilerInfo, Bundle options) throws RemoteException;
- 1、caller--当前应用的ApplicationThread对象mAppThread
- 2、callingPackage--调用ContextImpl.getBasePackageName(),获取当前Activity的包名
- 3、intent--启动Activity时,传递进来的参数
- 4、resolvedType--调用intent.resolvedTypeIfNeeded而获取
- 5、resultTo--来自当前Activity.mToken
- 6、resultWho--来自当前Activity.mEmbeddedID
- 7、requestCode=-1
- 8、flags=0
- 9、profilerInfo=null
- 10、options=null
这个方法中要做的事情就是IPC通信,利用Binder对象,调用
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
方法,把所需要的参数封装成Parcel对象,向AMS通信.
这里我们打包成Parcel对象有两个重要的信息:
- 1、caller--当前应用的ApplicationThread对象
- 2、callingPackage--调用当前ContextImpl.getBasePackageName(),获取当前Activity的包名.
7.3 transact
/frameworks/base/core/java/android/os/Binder.java
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);
if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}
7.4 onTransact
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (code == INTERFACE_TRANSACTION) {
reply.writeString(getInterfaceDescriptor());
return true;
} else if (code == DUMP_TRANSACTION) {
ParcelFileDescriptor fd = data.readFileDescriptor();
String[] args = data.readStringArray();
if (fd != null) {
try {
dump(fd.getFileDescriptor(), args);
} finally {
IoUtils.closeQuietly(fd);
}
}
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
return true;
} else if (code == SHELL_COMMAND_TRANSACTION) {
ParcelFileDescriptor in = data.readFileDescriptor();
ParcelFileDescriptor out = data.readFileDescriptor();
ParcelFileDescriptor err = data.readFileDescriptor();
String[] args = data.readStringArray();
ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
try {
if (out != null) {
shellCommand(in != null ? in.getFileDescriptor() : null,
out.getFileDescriptor(),
err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
args, resultReceiver);
}
} finally {
IoUtils.closeQuietly(in);
IoUtils.closeQuietly(out);
IoUtils.closeQuietly(err);
// Write the StrictMode header.
if (reply != null) {
reply.writeNoException();
} else {
StrictMode.clearGatheredViolations();
}
}
return true;
}
return false;
}
result的返回值生成最终调用了Binder的onTransact方法中.
而ActivityManagerNative类是继承自Binder类的.
八、ActivityManagerNative
/frameworks/base/core/java/android/app/ActivityManagerNative.java
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
...
}
8.1 onTransact
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case START_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String callingPackage = data.readString();
Intent intent = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
IBinder resultTo = data.readStrongBinder();
String resultWho = data.readString();
int requestCode = data.readInt();
int startFlags = data.readInt();
ProfilerInfo profilerInfo = data.readInt() != 0
? ProfilerInfo.CREATOR.createFromParcel(data) : null;
Bundle options = data.readInt() != 0
? Bundle.CREATOR.createFromParcel(data) : null;
int result = startActivity(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
可以看到,参数又回调进入这个类方法中,在方法中根据code走入了不同的case语句中.
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
}
case START_ACTIVITY_WITH_CONFIG_TRANSACTION:
{
...
int result = startActivityWithConfig(app, callingPackage, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, config, options, userId);
reply.writeNoException();
reply.writeInt(result);
return true;
}
case START_ACTIVITY_INTENT_SENDER_TRANSACTION:
{
...
int result = startActivityIntentSender(app, intent,
fillInIntent, resolvedType, resultTo, resultWho,
requestCode, flagsMask, flagsValues, options);
reply.writeNoException();
reply.writeInt(result);
return true;
}
result的返回值又调用了另外一个方法
这些方法其实都是IActivityManager中的抽象方法.
九、IActivityManager
/** { @hide} */
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
...
}
class ActivityManagerProxy implements IActivityManager
{
...
}
在源码中这两个类都继承了IActivityManager,而ActivityManagerProxy就是AMS在客户端中的代理.后续的调用就涉及到SystemServer进程以及AMS进程等进程间通信了.这里面也涉及到之前提到过的Binder机制.
分析到这儿,Launcher进程发起的启动App默认Activity的请求已经发送到了我们的服务端AMS中,具体一个App进程是如何被fork出并成功启动的呢?下篇文章我们会继续分析~