App启动流程:App进程内部操作-1

目录

  • 概述
  • 总结
  • 详细过程
  • 重要类说明

概述

在冷启动过程中,“当为App创建完进程”之后,就需要“激活处于焦点栈栈顶的待启动Activity”。关于冷启动过程的前两步操作,《为目标App启动做准备》《启动App进程》 的流程请点击查看。

由于“App进程内部操作”部分内容比较多一些,所以这部分的内容被分成了2个小章节来分析。
第一节:也就是本节是从“App进程启动完毕之后,从ActivityThread.main()开始” 至 “App进程接收到AMS通过scheduleLaunchActivity()发起的 LAUNCH_ACTIVITY 消息”为止。
第二节:《App启动流程:App进程内部操作-2》,则从“App接收到LAUNCH_ACTIVITY开始” 至 “通过Activity.handleResumeActivity()真正完成待启动Activity的实例化并执行其View树的绘制”为止。

当前源码的分析是基于 Android8.0。


总结

1:当Zygote进程创建并初始化完App进程后,就会通过反射执行ActivityThread.main()对main线程进行初始化。
2:通过ActivityManager.getService()获取AMS服务在本进程的BInder 代理,而后通过这个代理对象通知AMS执行attachApplication()操作。

这是一次IPC操作,从App进程切换至system_server进程

3:AMS接收到App进程发起的“attachApplication()操作”操作后会执行如下操作:
3.1:根据 调用者进程的pid,获取记录此进程信息的ProcessRecord。
3.2:注册“Binder服务死亡通知”,App进程挂掉之后其Binder服务也会随之停止掉,此时AMS需要接收到这个通知,然后去回收一些此进程使用的资源。
3.3:把当前App进程的ApplicationThread赋值给ProcessRecord中的thread。并重置此ProcessRecord中一些参数。
3.4:通过App进程的ApplicationThread服务在system_server进程的Binder代理对象,执行bindApplication()来通知App进程继续后续“绑定”操作。

这是一次IPC操作,从system_server进程切换至App进程

4:App进程接收到AMS发起的bindApplication()操作后会执行如下操作:
4.1:通过 ServiceManager.initServiceCache()更新系统服务在App进程的Binder缓存。
4.2:通过Handler消息机制,向App进程的主线程发一个“BIND_APPLICATION”消息,使操作切换至主线程继续后续执行。
5:App进程会通过handleBindApplication()处理bindApplication()操作。 具体所做的事情如下:
5.1:设置App进程名、为低内存设备关闭硬件加速功能、如果系统的版本号低于3.1,则更换AsyncTask的内部的线程池实现方法、系统版本号大于等于 3.0 的话,则开启严格模式来检查“是否在主线程开启了网络请求、初始化http代理、创建全局唯一Instrumentation实例 等。
5.2:通过LoadedApk.makeApplication()创建App进程的唯一Application实例,回调Application的attachBaseContext()、onCreate()。

App进程执行完bindApplication()操作后,又会回到system_server进程继续后续操作。

这些操作包括如下部分:
6.1:从“焦点栈”中获取“处于栈顶的待启动Activity对应的ActivityRecord”。
6.2:通知App进程执行“scheduleLaunchActivity()”操作,在App进程进行待启动Activity的实例化、各种生命周期方法的执行、相应PhoneWindow维护的View树的绘制等操作。

这是一次IPC操作,从system_server进程切换至App进程

7:App 进程接收到LLAUNCH_ACTIVITY消息之后,会在App进程内部的handleLaunchActivity()对待启动Activity进行激活等初始化操作。 具体操作如下:
7.1:从空闲消息处理器列表中 移除 “在主线程空闲时,执行强制GC操作的空闲消息处理器” 。
7.2:在创建待启动Activity之前,先获取WMS服务在本进程的Binder代理并保存至WindowManagerGlobal。
7.3:通过performLaunchActivity()初始化ContextImpl实例、对目标Activity进行初始化、执行Activity的绑定操作、执行Activity的相应生命周期方法、等Activity执行完Resume之后,才开始对Activity的View树进行App进程内部的测量、摆放、绘制等操作。并通过ViewRootImpl内部的“编舞者来接收IO硬件产生的“Vsync”刷新信号,进而对PhoneView维护的视图树进行周期性的刷新操作。
7.4:根据AMS传递给App 进程的startsNotResumed,来决定是否需要“禁止Resume待启动Activity,如果禁止就会执行该Activity的pasue操作”。
7.5:如果初始化Activity实例失败,告诉AMS需要 “移除” 此Activity对应保存在AMS 服务中的Activity栈中的ActivityRecord。


详细过程

当Zygote进程创建并初始化完App进程后,就会通过反射执行ActivityThread.main()对main线程进行初始化。

1.1.ActivityThread.main()

main()方法是子进程执行其主线程初始化的唯一入口。

源码

public static void main(String[] args) {
        //开始记录ActivityThread的初始化事件
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        ......
        //为主线程创建Looper
        Looper.prepareMainLooper();
        
        //初始化App进程内的ActivityThread唯一实例
        ActivityThread thread = new ActivityThread();
        //见小节[1.2]
        thread.attach(false);

        //sMainThreadHandler就是ActivityThead.H类的实例
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        //ActivityThread初始化完毕之后,结束记录该事件的耗时
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //启动主线程Looper,开始处理消息
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

1.2.ActivityThread.attach()

总结
1:通过ViewRootImpl.addFirstDrawHandler()注册“View树的首次绘制完毕回调事件”。
2:通过ViewRootImpl.addConfigCallback()注册“手机配置信息发生更改之后的回调事件。”
3:通过ActivityManager.getService()获取AMS服务在本进程的BInder 代理,而后通过这个代理对象通知AMS执行attachApplication()操作。

源码

private void attach(boolean system) {
        //把当前ActivityThread实例对象赋值给sCurrentActivityThread 属性。使用的时候方便通过currentActivityThread()获取。
        sCurrentActivityThread = this;
        //用于区分“当前进程是否是系统进程”。
        mSystemThread = system;
        if (!system) {
            //见小节[1.2.1]
            ViewRootImpl.addFirstDrawHandler(new Runnable() {
                @Override
                public void run() {
                    ensureJitEnabled();
                }
            });
            ......
            //见小节[1.3]
            final IActivityManager mgr = ActivityManager.getService();
            try {
             //见小节[2.1]
                mgr.attachApplication(mAppThread);
            } catch (RemoteException ex) {
                throw ex.rethrowFromSystemServer();
            }
            ......
        } else {
           //是系统进程的话,设置该进程的name为“system_process”。
           //可以启动一个模拟器或者刷root之后,打开可debug的进程之后,显示的那个“system_process”。如果要调试FrameWorker层的代码的话,那么此进程就是要debug的那个进程。
            android.ddm.DdmHandleAppName.setAppName("system_process",
                    UserHandle.myUserId());
            ......
        }

        ......
        //见小节[1.2.2]
        ViewRootImpl.ConfigChangedCallback configChangedCallback
                = (Configuration globalConfig) -> {
            synchronized (mResourcesManager) {
                // We need to apply this change to the resources immediately, because upon returning
                // the view hierarchy will be informed about it.
                if (mResourcesManager.applyConfigurationToResourcesLocked(globalConfig,
                        null /* compat */)) {
                    updateLocaleListFromAppContext(mInitialApplication.getApplicationContext(),
                            mResourcesManager.getConfiguration().getLocales());

                    // This actually changed the resources! Tell everyone about it.
                    if (mPendingConfiguration == null
                            || mPendingConfiguration.isOtherSeqNewer(globalConfig)) {
                        mPendingConfiguration = globalConfig;
                        sendMessage(H.CONFIGURATION_CHANGED, globalConfig);
                    }
                }
            }
        };
        ViewRootImpl.addConfigCallback(configChangedCallback);
    }

1.2.1.ViewRootImpl.addFirstDrawHandler():

总结:
1:注册“View树绘制第一帧时的回调事件”。
2:在View树绘制第一帧时,用于通知注册了此事件的被观察者,View开始绘制第一帧了。

源码

public static void addFirstDrawHandler(Runnable callback) {
        synchronized (sFirstDrawHandlers) {
            if (!sFirstDrawComplete) {
                sFirstDrawHandlers.add(callback);
            }
        }
    }

private void draw(boolean fullRedrawNeeded) {
        ......
        //通知那些注册了“绘制第一帧”事件的被观察者,开始绘制第一帧了
        if (!sFirstDrawComplete) {
            synchronized (sFirstDrawHandlers) {
                sFirstDrawComplete = true;
                final int count = sFirstDrawHandlers.size();
                for (int i = 0; i< count; i++) {
                    mHandler.post(sFirstDrawHandlers.get(i));
                }
            }
        }
    ......
    }

1.2.2.ViewRootImpl.addConfigCallback():添加当手机自身的配置信息发生改变之后(横竖屏切换、字体大小发生了更改等等)的回调事件。

Configuration:该类表示的是“设备的配置信息”。该类定义了许多与手机本身相关的配置信息。
1.orientation:表示当前手机的屏幕状态(横竖屏就是用这个来判断)。
2.densityDpi:屏幕密度(eg:440dpi)。
3.appBounds:屏幕大小。
4.screenLayout:该参数是一个“复合值”。具体的存储的信息如下:
4.1.屏幕整体大小:可通过该值与相应的mask进行位运算获得当前屏幕是“SMALL”、“NORMAL”、“LARGE”、“XLARGE”。
4.2.屏幕布局:表示当前屏幕中的元素是“从左往右布局”还是“从右往左布局”。取值范围为:“SCREENLAYOUT_LAYOUTDIR_LTR”、“SCREENLAYOUT_LAYOUTDIR_RTL”。
4.3.屏幕是否是圆形
5.fontScale:字体的缩放比率。

源码

public static void addConfigCallback(ConfigChangedCallback callback) {
        synchronized (sConfigCallbacks) {
            sConfigCallbacks.add(callback);
        }
    }

1.3.ActivityManager.getService():获取AMS服务在本进程的Binder代理。

源码

public static IActivityManager getService() {
        //调用IActivityManagerSingleton.get()会触发IActivityManagerSingleton中声明的create()。
        //见小节[1.3.1]
        return IActivityManagerSingleton.get();
    }

1.3.1.Singleton.create()

源码

private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    //见小节[1.3.2]
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    //见小节[1.3.7]
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };

1.3.2.ServiceManager.getService():获得相应系统服务在本进程的 IBinder 引用。

总结:
1:如果ServiceManager内部的HashMap缓存了此Binder服务的话,则返回。
2:如果没有,则通过 getIServiceManager().getService() 重新与system_server进程建立连接,获取相应服务在本进程的Binder代理。
3:这个Binder代理对象与系统服务对象不是一个。因为AMS运行在system_server进程,此对象运行在 App进程。采用“进程隔离”的方式,每个进程都有自己的 虚拟内存地址空间,且每个进程被分配的虚拟内存地址都不一样,这就导致每个进程可访问的内存区域是不一样的,进程之间没有交集,这就避免了 “修改进程A内存区域会影响到进程B内存中的数据”。

源码

public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            //此时,从本地服务缓存中获取的AMS服务的本地代理肯定为 null。
            //因为这些系统服务的本地代理还没有通过 initSerivceCache()缓存起来。
            if (service != null) {
                return service;
            } else {
                //见小节[1.3.3]、[1.3.6]
                return Binder.allowBlocking(getIServiceManager().getService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

1.3.3.ServiceManager.getIServiceManager():获取ServiceManager内部保存的IServiceManager实例。

总结:
1:如果IServiceManager实例已经初始化过了,则直接返回此实例。
2:如果还没初始化过,则需要先初始化然后返回此类实例。

源码

private static IServiceManager getIServiceManager() {
        //非首次调用,则返回此类实例
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // 初始化IServiceManager类实例
        //见小节[1.3.4]、[1.3.5]
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

1.3.4.BinderInternal.getContextObject():获取一个IServiceManager,通过它可以获取到一些其它系统服务。

总结:
1:该方法是一个native方法,用于获取“IServiceManager类型的实例”。
2:该IServiceManager接口的实例可以用来“查询其它服务”。

源码

/**
     * Return the global "context object" of the system.  This is usually
     * an implementation of IServiceManager, which you can use to find
     * other services.
     */
    public static final native IBinder getContextObject();

1.3.5.ServiceManagerNative.asInterface():获取一个IServiceManager类型的IBinder服务。

Binder使用上的简单介绍
1:Binder这种IPC方式采用的是CS架构。
2:IBinder表示“此类是可以用来进行IPC通信的,它提供了IPC通信的能力”。
2.1:Binder类实现了IBidner接口,实现了 “onTransact()”。
2.2:通常我们所提供的服务类要继承Binder,重写 OnTransact() 方法用于根据自己的业务处理来自Client端的请求。

总结
1:首先,判断通过“BinderInternal.getContextObject()”获得的IBinder服务是否是当前进程所创建,如果是直接返回此IBInder 服务。
2:如果不是,则返回一个 ServiceManagerProxy,把服务端在本进程的IBinder服务实例保存到这个代理对象中。这样做是为了 方便以后通过此IBinder实例与服务的所属进程进行通信。

源码

static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        //根据“descriptor”从本进程中查找该Binder服务。
        //1:如果此IBinder服务所属者是当前进程的话,则返回该服务。
        //2:如果不是,则返回ServiceManagerProxy。其中“obj”是服务端进程的IBinder服务在本进程的一个实例。
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        
        return new ServiceManagerProxy(obj);
    }

    //把IBinder服务在本进程的一个实例保存至ServiceManagerProxy中。
    //方便以后通过此IBinder实例与服务的所属进程进行通信。
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }

1.3.6.IServiceManager.getService():通过Binder IPC方式,根据name从system_server进程获取系统服务在本地进程的Binder代理对象。

源码

/**
     * Retrieve an existing service called @a name from the
     * service manager.  Blocks for a few seconds waiting for it to be
     * published if it does not already exist.
     */
    public IBinder getService(String name) throws RemoteException;

1.3.7.IActivityManager.Stub.asInterface():

总结:
1:把获取的IBinder对象封装到AMS服务在子进程的Binder代理对象中。
2:此代理对象的实际类型为 IActivity.Stub.Proxy。
3:此代理对象与AMS对象一样都实现了IActivityManager接口,此接口定了AMS向外提供了哪些操作。这样做的好处是“在使用的时候,就可以直接知道可以使用AMS提供的哪些方法了”。

说明:
1:从8.0开始,AMS这种用于IPC通信的系统服务的实现方式改为AIDL 来实现。
2:8.0之前AMS内提供的 用于处理进程间操作的业务 全部是在ActivityManagerNative内部来实现,而从8.0开始采用AIDL之后,AMS直接继承自IActivityService.Stub原来处理进程间操作的业务全部挪到AMS来中完成。

因为看不到IActivityService.Stub的内部实现,所以以下代码就摘抄了一个AS编译的AIDL文件生成的的asInterface()实现(通过AIDL方式编译的此方法的实现格式是一样)。

public static sj.IMyAidlInterface asInterface(android.os.IBinder obj) {
    //判断IBinder服务是否为空
    if ((obj==null)) {
        return null;
    }
    
    //查询此服务是否是本进程创建的
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

    if (((iin!=null)&&(iin instanceof sj.IMyAidlInterface))) {
        return ((sj.IMyAidlInterface)iin);
    }
    
    //此服务不是本进程创建的话,则返回与之对应的Proxy对象。
    return new sj.IMyAidlInterface.Stub.Proxy(obj);
}

......

Proxy(android.os.IBinder remote) {
      mRemote = remote;
}

2.1.ActivityManagerService.attachApplication()

总结:
1:通过ActivityManager.getService()获取AMS服务在本进程的Binder代理对象后,调用该代理对象的 attachApplication() 就会进行一次进程切换。
2:App进程会被阻塞住,一直等到system_server进程内部的AMS.attachApplication()执行完毕为止。

参数说明:
IApplicationThread threa:App进程的ApplicationThread唯一实例。关于ApplicationThread的介绍请查看 本章-重要类说明

源码

@Override
    public final void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            //获取调用者进程的pid(已经启动的App进程的id)。
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            //见小节[2.2]
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }

2.2.ActivityManagerService.attachApplicationLocked()

总结:
1:根据 调用者进程的pid,获取记录此进程信息的ProcessRecord。如果获取的ProcessRecord为null的话,则表示“之前创建App进程那步出现了问题(ProcessRecord用于记录App运行在的进程信息)”,这种情况直接返回不再继续后续操作。
2:注册“Binder服务死亡通知”。这里的“服务端”指的是App进程的ApplicationThread实例(ApplicationThread继承IApplicationThread.Stub,它是在此Binder IPC通信中扮演的是服务端角色)。App进程挂掉之后其Binder服务也会随之停止掉,此时AMS需要接收到这个通知,然后去回收一些此进程使用的资源(eg:重置此进程对应的ProcessRecord中的数据,进程被kill掉之后其ProcessRecord并不会从mPidsSelfLocked缓存中移除)。
3:把当前App进程的ApplicationThread赋值给ProcessRecord中的thread。并重置此ProcessRecord中一些参数。
4:通过App进程的ApplicationThread服务在system_server进程的Binder代理对象,执行bindApplication()来通知App进程继续后续“绑定”操作。
4.1:如果执行“bindApplication()”之后的绑定操作失败了则:取消掉已经注册的 Binder服务死亡通知。调用startProcessLocked()再通知Zygote进程重新走一遍fork子进程流程。

源码

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {

        // 根据调用者进程的pid,获取记录此进程信息的ProcessRecord.
        ProcessRecord app;
        long startTime = SystemClock.uptimeMillis();
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid);
            }
        } else {
            app = null;
        }

        if (app == null) {  
            ......
            //如果获取的ProcessRecord为null的话,则表示“之前创建App进程那步出现了问题(ProcessRecord用于记录App运行在的进程信息)”,这种情况直接返回不再继续后续操作。
            return false;
        }

       ......
        try {
            //注册“Binder服务死亡通知”。
            //这里的“服务端”指的是App进程的ApplicationThread实例(ApplicationThread继承IApplicationThread.Stub,它是在此Binder IPC通信中扮演的是服务端角色。App进程挂掉之后其Binder服务也会随之停止掉,此时AMS需要接收到这个通知,然后去回收一些此进程使用的资源(eg:重置此进程对应的ProcessRecord中的数据,进程被kill掉之后其ProcessRecord并不会从mPidsSelfLocked缓存中移除)。)
            AppDeathRecipient adr = new AppDeathRecipient(
                    app, pid, thread);
            thread.asBinder().linkToDeath(adr, 0);
            app.deathRecipient = adr;
        } catch (RemoteException e) {
            ......
            return false;
        }

        ......
        //把当前App进程的ApplicationThread赋值给ProcessRecord中的thread。
        app.makeActive(thread, mProcessStats);
        //ProcessRecord一些参数的重置操作。
        app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
        app.forcingToImportant = null;
        updateProcessForegroundLocked(app, false, false);
        app.hasShownUi = false;
        app.debugging = false;
        app.cached = false;
        app.killedByAm = false;
        app.killed = false;

        ......

        try {
           ......
            //不清楚ProcessRecord中ActiveInstrumentation类型的 instr是做什么的。
            //但是无论此属性是否为null,AMS服务都会通过App进程的ApplicationThread服务在system_server进程的Binder代理对象执行bindApplication()来通知App进程继续后续操作。
            if (app.instr != null) {
                //见小节[2.4]
                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), //见小节[2.3]
                        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), //见小节[2.3]
                        mCoreSettingsObserver.getCoreSettingsLocked(),
                        buildSerial);
            }
        ......
        } catch (Exception e) {
             //如果此操作出现了问题导致抛出了异常情况。
            app.resetPackageList(mProcessStats);
            //取消掉已经注册的 Binder服务死亡通知。
            app.unlinkDeathRecipient();
            //调用startProcessLocked()再通知Zygote进程重新fork一个新的子进程。
            startProcessLocked(app, "bind fail", processName);
            return false;
        }

        boolean badApp = false;
        boolean didSomething = false;
        
        //See if the top visible activity is waiting to run in this process...
        //激活处于“焦点栈栈顶的待启动Activity”
        //见小节[3.1]
        if (normalMode) {
            try {
                if (mStackSupervisor.attachApplicationLocked(app)) {
                    didSomething = true;
                }
            } catch (Exception e) {
                ......
            }
        }
        ......

        return true;
    }

2.3.getCommonServicesLocked.getCommonServicesLocked():获得一些公共的系统服务。

总结:
1:获得一些公共的系统Binder服务。
1.1:如果isolated为true的话,则只把PMS服务的IBinder对象回传给App进程。
1.2:如果isolated为fasle的话,则把PMS、WMS、AlarmManagerService(闹钟服务)的IBinder对象回传给App进程。
2:获得的这些服务,会通过Binder这种IPC方式回传给App进程,App进程接收到AMS发起的binderApplication()请求后,会首先通过 ServiceManager.initServiceCache()更新系统服务在App进程的Binder缓存。

源码

private HashMap<String, IBinder> getCommonServicesLocked(boolean isolated) {
        //如果 isolated为true的话,则只把系统服务中的“PMS”对应的Binder对象存储到Map中。
        if (isolated) {
            if (mIsolatedAppBindArgs == null) {
                mIsolatedAppBindArgs = new HashMap<>();
                mIsolatedAppBindArgs.put("package", ServiceManager.getService("package"));
            }
            return mIsolatedAppBindArgs;
        }

        if (mAppBindArgs == null) {
            mAppBindArgs = new HashMap<>();

           //如果 isolated为false的话,则把系统服务中的“PMS、WMS、AlarmManagerService”对应的Binder对象存储到Map中。
            mAppBindArgs.put("package", ServiceManager.getService("package"));
            mAppBindArgs.put("window", ServiceManager.getService("window"));
            mAppBindArgs.put(Context.ALARM_SERVICE,
                    ServiceManager.getService(Context.ALARM_SERVICE));
        }
        return mAppBindArgs;
    }

2.4.ApplicationThread.bindApplication()

总结:
1:通过 ServiceManager.initServiceCache()更新系统服务在App进程的Binder缓存。
2:通过Handler消息机制,向App进程的主线程发一个“BIND_APPLICATION”消息,使操作切换至主线程继续后续执行。
3:该操作是一次IPC过程,涉及到进程切换,从AMS所在的system_server进程切换至App进程。AMS要想主动发起与App进程的通信,就得借助于Binder这种IPC方式,因为ApplicationThread承担的是服务端的角色,客户端发起的请求,服务端接收后都会把这些操作扔到Bidner线程池中执行,这样做的好处是提高了服务端的“并发”性能。

源码

public final void bindApplication(String processName, ApplicationInfo appInfo,
                List<ProviderInfo> providers, ComponentName instrumentationName,
                ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                IInstrumentationWatcher instrumentationWatcher,
                IUiAutomationConnection instrumentationUiConnection, int debugMode,
                boolean enableBinderTracking, boolean trackAllocation,
                boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                String buildSerial) {

            if (services != null) {
                //通过 ServiceManager.initServiceCache()更新系统服务在App进程的Binder缓存。
                 //见小节[2.5]
               ServiceManager.initServiceCache(services);
            }

            AppBindData data = new AppBindData();
            ......
            //见小节[2.6]
            sendMessage(H.BIND_APPLICATION, data);
        }

2.5.ServiceManager.initServiceCache():更新系统服务在App进程的Binder缓存。

源码

public static void initServiceCache(Map<String, IBinder> cache) {
        if (sCache.size() != 0) {
            throw new IllegalStateException("setServiceCache may only be called once");
        }
        sCache.putAll(cache);
    }

2.6.ActivityThread.handleBindApplication()

总结:
1:做一些准备操作。 记录进程的开始时间、设置App进程名、为低内存设备关闭硬件加速功能、如果系统的版本号低于3.1,则更换AsyncTask的内部的线程池实现方法系统版本号大于等于 3.0 的话,则开启严格模式来检查“是否在主线程开启了网络请求、初始化http代理、创建全局唯一Instrumentation实例 等。
2:通过LoadedApk.makeApplication()创建App进程的唯一Application实例。

源码

private void handleBindApplication(AppBindData data) {
        ......
        //记录进程的开始时间。
        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
        ......
        //设置App进程名
        Process.setArgV0(data.processName);
        //设置App进程在ddms模块显示的进程名
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());

        if (data.persistent) {
            //为 低内存设备关闭硬件加速功能,这是为了节省资源开销。
            if (!ActivityManager.isHighEndGfx()) {
                ThreadedRenderer.disable(false);
            }
        }

        ......

        // 如果系统的版本号低于3.1,则设置AsyncTask的内部的线程池实现方法。
        if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
            AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
        }

        ......

        //系统版本号大于等于 3.0 的话,则开启严格模式来检查“是否在主线程开启了网络请求,如果开始了会抛出NetworkOnMainThreadException”。
        if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
            StrictMode.enableDeathOnNetwork();
        }

        //??
        if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
            StrictMode.enableDeathOnFileUriExposure();
        }

        ......
        //如果App可debug调试的话,则进行debug调试的相关设置
        if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) {
            ......
        }

        // 根据App是否可debug调试,来设置是否可以trace进程信息。
        boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
        Trace.setAppTracingAllowed(isAppDebuggable);
        if (isAppDebuggable && data.enableBinderTracking) {
            Binder.enableTracing();
        }

        //初始化http代理
        final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
        if (b != null) {
            // In pre-boot mode (doing initial launch to collect password), not
            // all system is up.  This includes the connectivity service, so don't
            // crash if we can't get it.
            final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
            try {
                final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                Proxy.setHttpProxySystemProperty(proxyInfo);
            } catch (RemoteException e) {
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                throw e.rethrowFromSystemServer();
            }
        }

        ......
        
        // 创建全局唯一Instrumentation实例,该mInstrumentation会在Activity创建完毕执行其attach()时保存至Activity内部。
        if (ii != null) {
            try {
                //创建Instrumentation实例
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            } catch (Exception e) {}
            ......
            mInstrumentation.init(this, instrContext, appContext, component,
                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
           ......
        } else {
            mInstrumentation = new Instrumentation();
        }

        ......
        try {
            //创建App进程的唯一Application实例
            //见小节[2.7]
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            //回调Instrumentation.onCreate()
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
           ......
            //回调Application的onCreate()生命周期方法
            try {
                //见小节[2.8]
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                ......
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
        ......
    }

2.7.LoadedApk.makeApplication()

总结:
1:该方法做事是:创建Applicaton实例并执行该实例的attachBaseContext()与onCreate()生命周期方法。
2:判断App进程的Application是否实例化了,如果已经创建了则返回该Application。
3:系统采用反射的方式实例化Applation实例,第一步就是先指定“实例化Application的类的全限定名”。
4:通过Instrumentation.newApplication()初始化Application实例并回调其attachBaseContext()。
5:保存创建完毕的Application实例。
6:通过Instrumentation.callApplicationOnCreate()回调Application的onCreate()。

源码

public Application makeApplication(boolean forceDefaultAppClass,
            Instrumentation instrumentation) {
        //判断App进程的唯一Application是否创建了,如果创建则直接返回。
        //一个进程只有一个Application实例。
        if (mApplication != null) {
            return mApplication;
        }
    
       //记录 创建Application花费的时间
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "makeApplication");

        Application app = null;
        
       //指定“实例化Application的类的全限定名”。
       //ApplicationInfo记录的是Manifest文件中<application>中的属性信息。
       //如果“<application>未指定自定义Applcation”或者 “强制使用默认的Application”来初始化Application实例的话,则使用默认Application来

初始化
        String appClass = mApplicationInfo.className;
        if (forceDefaultAppClass || (appClass == null)) {
            appClass = "android.app.Application";
        }

        try {
            java.lang.ClassLoader cl = getClassLoader();
            if (!mPackageName.equals("android")) {
                Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                        "initializeJavaContextClassLoader");
                initializeJavaContextClassLoader();
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            //创建ContextImpl实例。
            ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
            //见小节[2.7.1]
            app = mActivityThread.mInstrumentation.newApplication(
                    cl, appClass, appContext);
            appContext.setOuterContext(app);
        } catch (Exception e) {
            ......
        }

        mActivityThread.mAllApplications.add(app);
        //保存创建完毕的Application实例
        mApplication = app;
        
        //传入的instrumentation为null,不走这里
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                ......
            }
        }

        ......

        return app;
    }

2.7.1.Instrumentation.newApplication()

总结:实例化Application实例并回调Application的attachBaseContext()生命周期方法。

源码

public Application newApplication(ClassLoader cl, String className, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        return newApplication(cl.loadClass(className), context);
    }


static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }


/* package */ final void attach(Context context) {
        attachBaseContext(context);
        mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
    }

2.8.Instrumentation.callApplicationOnCreate()

总结:实例化Application实例并回调Application的attachBaseContext()生命周期方法。

源码

public void callApplicationOnCreate(Application app) {
        app.onCreate();
    }

3.1.ActivityStackSupervisor.attachApplicationLocked()

总结:从“焦点栈”中获取“处于栈顶的待启动Activity对应的ActivityRecord”并激活此ActivityRecord描述的App进程的Activity。
1:一个ActivityDisplay实例表示一块屏幕,一个ActivityDisplay实例中存储了多个ActivityStack实例。
2:遍历每个ActivityDisplay中的ActivityStack集合,找到ActivityDisplay中的那个“焦点栈(ActivityStackSupervisor.mFocusedStack)”。
3:找到“焦点栈”之后,调用其topRunningActivityLocked()从其内部保存TaskRecord列表中找到“处于栈顶的待启动Activity对应的ActivityRecord”。
4:调用ActivityStackSupervisor.realStartActivityLocked()激活处于焦点栈的待启动Activity。

源码

boolean attachApplicationLocked(ProcessRecord app) throws RemoteException {
        //获取App进程名
        final String processName = app.processName;
        boolean didSomething = false;
        //遍历ActivityDisplay集合。
        //一个ActivityDisplay实例表示一块屏幕,一个ActivityDisplay实例中存储了多个ActivityStack实例。
        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
            ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
            //遍历每个ActivityDisplay中的ActivityStack集合。
            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
                final ActivityStack stack = stacks.get(stackNdx);
                //找到ActivityDisplay中的那个“焦点栈”。
                if (!isFocusedStack(stack)) {
                    continue;
                }
                //从“焦点栈”中获取“处于栈顶的待启动Activity”。
                ActivityRecord hr = stack.topRunningActivityLocked();
                if (hr != null) {
                    //待启动Activity对应的ActivityRecord信息只是添加到了AMS中的“Activity栈”中(具体是保存到ActivityTask中的TaskRecord列表中)。
                    //该Activity实例还没有在App进程进行实例化,此时“ActivityRecord中保存的用于描述其所属进程的ProcessRecord还未被赋值”。所以ActivityRecord.app为null。
                    //检查“待启动Activity是否未被添加到所属进程”、“App进程的uid与待启动Activity在Manifest中声明的uid一致”、“App进程名与从Manifest文件中解析出的进程名一致”这3个条件是否都满足。
                    if (hr.app == null && app.uid == hr.info.applicationInfo.uid
                            && processName.equals(hr.processName)) {
                        try {
                            //见小节[3.2]
                            if (realStartActivityLocked(hr, app, true, true)) {
                                didSomething = true;
                            }
                        } catch (RemoteException e) {
                            Slog.w(TAG, "Exception in new application when starting activity "
                                  + hr.intent.getComponent().flattenToShortString(), e);
                            throw e;
                        }
                    }
                }
            }
        }
        if (!didSomething) {
            ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
        }
        return didSomething;
    }

3.2.ActivityStackSupervisor.realStartActivityLocked()

总结:
1:检查是否“所有的ActivityStack中的mPausingActivity表示的正在处于暂停状态的Activity执行完毕暂停操作了”。如果还有ActivityStack种的Activity正在执行暂停操作的话,则先不会执行待启动 Activity 的激活操作。
2:把描述App进程信息的ProcessRecord对象保存至ActivityRecord中。
3:通知App进程执行“ scheduleLaunchActivity()”操作,在App进程进行待启动Activity的实例化、各种生命周期方法的执行、相应PhoneWindow维护的View树的绘制等操作。**

源码

final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
        //检查是否“所有的ActivityStack中的mPausingActivity表示的正在处于暂停状态的Activity执行完毕暂停操作了”
        if (!allPausedActivitiesComplete()) {
            ......
            return false;
        }

        ......
    
    //把描述App进程信息的ProcessRecord对象保存至ActivityRecord中。
    r.app = app;
    ......
        try {
            ......
            //见小节[3.3]
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    // TODO: Have this take the merged configuration instead of separate global and
                    // override configs.
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);

           ......
        } catch (RemoteException e) {
            ......
        }

        ......
        //andResume为true,走这里
        //见小节[4.1]
        if (andResume) {
            stack.minimalResumeActivityLocked(r);
        } else {
            ......
            r.state = PAUSED;
        }

        ......

        return true;
    }

3.3.ApplicationThread.scheduleLaunchActivity()

总结:通过Binder IPC方式,通知App进程执行待启动Activity的启动操作。
1:缓存AMS传递给App进程的参数信息(eg:startsNotResumed被赋值为了false,该值表示“是否需要禁止Resume待启动Activity”。如果禁止就会执行该Activity的pasue操作。true:禁止,false:不禁止)。
1:ApplicationThread作为Binder通信的服务端,其内部操作是通过Handler消息机制,向App进程的主线程发一个“LAUNCH_ACTIVITY”消息,使操作切换至主线程继续后续执行。
2:该操作是一次IPC过程,涉及到进程切换,从AMS所在的system_server进程切换至App进程。AMS要想主动发起与App进程的通信,就得借助于Binder这种IPC方式,因为ApplicationThread承担的是服务端的角色,客户端发起的请求,服务端接收后都会把这些操作扔到Bidner线程池中执行,这样做的好处是提高了服务端的“并发”性能。

源码

public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

           ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;
            r.persistentState = persistentState;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;
            
            //该值为false,在AMS所在的system_server通过Binder请求App进程的时候,notResumed为赋值为了“!andResume”,而andResume为true。
            //该值表示“是否禁止Resume待启动Activity”,如果禁止就会执行该Activity的pasue操作。true:禁止,false:不禁止。
            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profilerInfo = profilerInfo;

            r.overrideConfig = overrideConfig;
            updatePendingConfiguration(curConfig);

            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

由于文章字数过长,请查看App启动流程:App进程内部操作-2


重要类说明

ApplicationThread
  • 从Android8.0开始,很多用于Binder IPC的类改用AIDL的方式实现,其中ApplicationThread的实现也发生了改变。
  • 该类由原来继承自ApplicationThreadNative 改为在8.0版本继承自 IApplicationThread.Stub。但是不管怎么变,我们可以知道 ApplicationThread还是用来做IPC通信的,且它在Binder这种CS架构中担任的是 服务端角色。

ServiceManager
  • IServiceManager sServiceManager:该IServiceManager接口的实例可以用来“查询其它服务”(eg:从system_server进程获取AMS服务的本进程代理)。
  • HashMap<String, IBinder> sCache:用于缓存系统服务在本进程的Binder代理对象。
  • initServiceCache():缓存系统服务在App进程的Binder服务。当App冷启动完毕后,会执行“AMS.attachApplication()”,在该方法内部经过层层调用,会通过传入的App进程内唯一的ApplicationThread实例通过Binder这种IPC方式,回调执行子进程的 bindApplication() 用于“初始化App进程的唯一Application实例”。在初始化之前,会首先执行 SystemService.initServiceCache()缓存系统服务在App进程的Binder服务”。
  • getService():获取系统服务在本进程的Binder代理对象。
    1:如果ServiceManager内部的HashMap缓存了此Binder服务的话,则返回。
    2:如果没有,则通过 getIServiceManager().getService() 通过Binder驱动获取Native层ServiceManager的Binder服务后,再通过ServiceManager获取已向其注册的相应Binder服务在本进程的Binder代理对象。
    3:这个Binder代理对象与系统服务对象不是一个。因为AMS运行在system_server进程,此对象运行在 App进程。采用“进程隔离”的方式,每个进程都有自己的 虚拟内存地址空间,且每个进程被分配的虚拟内存地址都不一样,这就导致每个进程可访问的内存区域是不一样的,进程之间没有交集,这就避免了 “修改进程A内存区域会影响到进程B内存中的数据”。

Instrumentation

作用:
1:用于检测,Application、Activity各个生命周期方法的执行。
之所以能检测,是因为在Instrumentation内部的相应方法内部,会执行Application、Activity相应生命周期方法的执行。
也可以说“Application、Activity各个生命周期方法的执行是通过Instrumentation中的相应方法来触发的”。
2:用于检测,Activity启动结果是否成功。
Activity 通过Intent进行跳转的操作,被封装到该类的execStartActivity()中去进一步执行。
2.1:在启动目标Activity时会通过执行该类的execStartActivity()。
2.2:首先,通过AMS.startActivity()启动目标Activity。不论启动是否成功,都会返回一个int类型的result。
2.3:其次,会通过checkStartActivityResult()来检查Activity启动结果。
返回的启动结果在[-100,-1]范围的话,则会根据实际的res值抛出相应的异常,用于提示此次启动Activity具体是因为什么问题而导致启动失败了。
(像是常见的,Activity没有在manifest文件注册导致的抛出ActivityNotFoundException的原因等)。
3:其他使用场景:
3.1:自定义检测器(这个好像是用于Android 测试的),可以监听Application、Activity的各个生命周期方法调用。

就像该类的说明一下,此类是“实现应用程序检测代码的基类”。
要想自定义“检测器的话”,可以在Manifest文件中通过<instrumentation>指定具体的自定义检测器。
3.2:可以Hook Instrumentation来达到监听Application、Activity 的目的。因为它在App进程中是唯一的,Application、Activity各个生命周期方法的执行是通过Instrumentation中的相应方法来触发的。所以说Instrumentation作为Hook点来说是比较“稳定”的,因为它在App进程中只有一个实例。


ActivityClientRecord :
  • 在App进程每个Acticity组件都有一个该类的对象来对已启动Activity组件进行描述。
  • 该类与ActivityRecord相对应。
  • 该类存储在App进程,而ActivityRecord则存储在SystemServer进程中的AMS中的Activity栈结构中。

Activity

重要属性:
1:mStartedActivity
作用:该属性表示“是否启动了其他Activity”。该属性只有在Activity的几个startXX()(
startActivityForResult()、startActivityIfNeeded()、startActivityForResultAsUser()等等)方法被重置为true,默认值为false。
1:如果mStartedActivity为true,则表示启动了其他Activity,进一步则会使当前Activity不可见。
2:如果为false,则表示可见。


ThreadedRenderer
StrictMode
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容