深入浅出Android底层(十)-Android系统启动过程--Launcher进程

395 阅读10分钟

前言

持续创作,加速成长!这是我参与「掘金日新计划 · 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>

image.png

可以看到 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

image.png

/** { @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出并成功启动的呢?下篇文章我们会继续分析~