Home界面的启动
继上篇文章Launcher进程的启动,我们继续分析Home界面的启动。
public final class ActivityThread {
...... public static final void main(String[] args) {
SamplingProfilerIntegration.start(); Process.setArgV0("<pre-initialized>"); Looper.prepareMainLooper();
if (sMainThreadHandler == null) {
sMainThreadHandler = new Handler();
} ActivityThread thread = new ActivityThread();
thread.attach(false); if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop(); if (Process.supportsProcesses()) {
throw new RuntimeException("Main thread loop unexpectedly exited");
} thread.detach();
String name = (thread.mInitialApplication != null)
? thread.mInitialApplication.getPackageName()
: "<unknown>";
Slog.i(TAG, "Main thread of " + name + " is now exiting");
} ......
}
thread.attach函数例如以下:
private final void attach(boolean system) {
sThreadLocal.set(this);
mSystemThread = system;
if (!system) {
......
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
}
} else {
......
}
......
}
static public IActivityManager getDefault()
{
if (gDefault != null) {
//if (Config.LOGV) Log.v(
// "ActivityManager", "returning cur default = " + gDefault);
return gDefault;
}
IBinder b = ServiceManager.getService("activity");
if (Config.LOGV) Log.v(
"ActivityManager", "default service binder = " + b);
gDefault = asInterface(b);
if (Config.LOGV) Log.v(
"ActivityManager", "default service = " + gDefault);
return gDefault;
}
static public IActivityManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
} return new ActivityManagerProxy(obj);
}
在ActivityThread类的成员函数attach中,调用ActivityManagerNative类的静态成员函数getDefault来获得ActivityMangerService的一个代理对象。代理对象的类型为ActivityMangerProxy。
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
mgr.attachApplication(mAppThread)实际上调用的是ActivityManagerProxy的attachApplication,例如以下:
class ActivityManagerProxy implements IActivityManager
{ public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
......
}
当中app为:
final ApplicationThread mAppThread = new ApplicationThread();
继承于ApplicationThreadNative,ApplicationThreadNative继承于Binder实现了IApplicationThread。
因为是同步传输,所以Launcher进程子线程睡眠等待,程序继续运行Looper.loop(),此时主线程的消息循环机制创立。
此时System进程Binder主线程池和子线程池都开启了,正在等待来自Launcher进程的请求。
System进程。接收到请求后,如上图的Binder进程间通信的省略步骤一样。会运行例如以下代码,是在System进程的一个子线程中运行:
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
......
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case ATTACH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IApplicationThread app = ApplicationThreadNative.asInterface(
data.readStrongBinder());
if (app != null) {
attachApplication(app);
}
reply.writeNoException();
return true;
}
.......
}
首先生成BinderProxy对象。里面的mObject指向代理对象。向上转型为IBinder。
然后生成ApplicationThreadProxy对象,里面mRemote指向BinderProxy对象。
因为ActivityManagerService类继承于ActivityManagerNative类,所以attachApplication。实际上运行的是位于ActivityManagerService中的。
public final class ActivityManagerService extends ActivityManagerNative{ public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
.....
}
这里将操作转发给attachApplicationLocked函数,例如以下:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback { ...... private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);//取回ProcessRecord对象。保存在app中,app就是用来描写叙述新创建的应用程序进程的
}
} else if (mStartingProcesses.size() > 0) {
......
} else {
......
} if (app == null) {
......
return false;
} ...... String processName = app.processName;
try {
thread.asBinder().linkToDeath(new AppDeathRecipient(
app, pid, thread), 0);
} catch (RemoteException e) {
......
return false;
} ...... app.thread = thread;//thread设置为參数thread所指向的一个ApplicationThread代理对象 ......
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);//删除ActivityMangerService所运行在的线程的消息队列中PROC_START_TIMEOUT_MSG消息
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info); ......
thread.bindApplication(processName, app.instrumentationInfo != null
? app.instrumentationInfo : app.info, providers,
app.instrumentationClass, app.instrumentationProfileFile,
app.instrumentationArguments, app.instrumentationWatcher, testMode,
isRestrictedBackupMode || !normalMode,
mConfiguration, getCommonServicesLocked()); boolean badApp = false;
boolean didSomething = false; // See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);//位于栈顶的ActivityRecord是Home界面的ActivityRecord
if (hr != null && normalMode) {
if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
&& processName.equals(hr.processName)) {
try {
if (mMainStack.realStartActivityLocked(hr, app, true, true)) {//最后走这里
didSomething = true;
}
} catch (Exception e) {
......
}
} else {
......
}
} ...... return true;
} ...... }
在System进程的启动流程第二部分,最后一部分,ActivityManager以这个PID为keyword将一个ProcessRecord对象保存在了成员变量mPidsSelfLocked中。
所以首先通过參数pid将这个ProcessRecord对象取回来。而且保存在app中。
然后对app初始化,当中最重要的是将它的成员变量thread设置为參数thread所指向的一个ApplicationThread代理对象。
这样,ActivityManagerService以后就能够通过这个ApplicationThread代理对象来和新创建的应用程序进程进行通信了。
还记得在System进程的启动流程第二部分,最后一部分,会向ActivityManagerService所运行的线程的消息队列发送一个类型为PROC_START_TIMEOUT_MSG的消息。而且指定这个消息在PROC_START_TIMEOUT毫秒之后处理。
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
这里通过下面代码来删除ActivityMangerService所运行在的线程的消息队列中PROC_START_TIMEOUT_MSG消息,因为新的应用程序进程已经在规定的时间内启动起来了。
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app)
最后通过ActivityStack类的成员函数realStartActivityLocked来请求该应用程序进程启动一个Activity。
public class ActivityStack { ...... final boolean realStartActivityLocked(ActivityRecord r,
ProcessRecord app, boolean andResume, boolean checkConfig)
throws RemoteException { ...... r.app = app;//r的成员变量app的值设置为參数app,表示它描写叙述的Activity组件是在參数app所描写叙述的应用程序进程中启动的 ...... int idx = app.activities.indexOf(r);
if (idx < 0) {
app.activities.add(r);//将该Activity加入到參数app所描写叙述的应用程序进程的Activity组件列表中
} ...... try {
...... List<ResultInfo> results = null;
List<Intent> newIntents = null;
if (andResume) {
results = r.results;
newIntents = r.newIntents;
} ...... app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
System.identityHashCode(r),
r.info, r.icicle, results, newIntents, !andResume,
mService.isNextTransitionForward()); ...... } catch (RemoteException e) {
......
} ...... return true;
} ...... }
这里终于通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中,注意,这里的第二个參数r,是一个ActivityRecord类型的Binder对象。用来作来这个Activity的token值。
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward)
throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
intent.writeToParcel(data, 0);
data.writeStrongBinder(token);
data.writeInt(ident);
info.writeToParcel(data, 0);
data.writeBundle(state);
data.writeTypedList(pendingResults);
data.writeTypedList(pendingNewIntents);
data.writeInt(notResumed ? 1 : 0);
data.writeInt(isForward ? 1 : 0);
mRemote.transact(SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
其Binder类图例如以下:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
我们传递的数据token。是一个ActivityRecord类型的Binder对象。例如以下图:
1、运行完scheduleLaunchActivity,此时SystemServer进程向Launcher进程发送了两个Binder请求,一个是SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION,一个是ATTACH_APPLICATION_TRANSACTION的返回值。
2、因为Launcher进程在子线程中等待Binder进程间通信请求,所以分别处理这个两个请求,对于第二个请求的处理代码例如以下:
class ActivityManagerProxy implements IActivityManager
{ public void attachApplication(IApplicationThread app) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(app.asBinder());
mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
......
}
3、对于第一个Binder请求处理例如以下,如Binder类图所看到的,開始运行例如以下代码:
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
........
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case SCHEDULE_LAUNCH_ACTIVITY_TRANSACTION:
{
data.enforceInterface(IApplicationThread.descriptor);
Intent intent = Intent.CREATOR.createFromParcel(data);
IBinder b = data.readStrongBinder();
int ident = data.readInt();
ActivityInfo info = ActivityInfo.CREATOR.createFromParcel(data);
Bundle state = data.readBundle();
List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
boolean notResumed = data.readInt() != 0;
boolean isForward = data.readInt() != 0;
scheduleLaunchActivity(intent, b, ident, info, state, ri, pi,
notResumed, isForward);
return true;
}
.....
}
当中b为一个BinderProxy的Binder代理对象。指向了ActivityManagerService中与Launcher进程相应的一个AcitivityRecord对象,如上图所看到的。
因为ApplicationThread继承于ApplicationThreadNative,所以真正运行的是ApplicationThread里面的scheduleLaunchActivity方法。
public final class ActivityThread { ...... private final class ApplicationThread extends ApplicationThreadNative { ...... // we use token to identify this activity without having to send the
// activity itself back to the activity manager. (matters more with ipc)
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {
ActivityClientRecord r = new ActivityClientRecord(); r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
r.state = state; r.pendingResults = pendingResults;
r.pendingIntents = pendingNewIntents; r.startsNotResumed = notResumed;
r.isForward = isForward; queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
} ...... } ......
}
函数首先创建一个ActivityClientRecord实例,而且初始化它的成员变量,然后调用ActivityThread类的queueOrSendMessage函数进一步处理。
public final class ActivityThread { ...... private final class ApplicationThread extends ApplicationThreadNative { ...... // if the thread hasn't started yet, we don't have the handler, so just
// save the messages until we're ready.
private final void queueOrSendMessage(int what, Object obj) {
queueOrSendMessage(what, obj, 0, 0);
} ...... private final void queueOrSendMessage(int what, Object obj, int arg1, int arg2) {
synchronized (this) {
......
Message msg = Message.obtain();
msg.what = what;
msg.obj = obj;
msg.arg1 = arg1;
msg.arg2 = arg2;
mH.sendMessage(msg);
}
} ...... } ......
}
因为眼下是在Binder子线程池中处理的请求。所以queueOrSendMessage眼下处于子线程,大家知道mH是主线程中Handler,刚刚完毕了Loop.loop()进入了消息循环。
public final class ActivityThread { ...... private final class H extends Handler { ...... public void handleMessage(Message msg) {
......
switch (msg.what) {
case LAUNCH_ACTIVITY: {
ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo);
handleLaunchActivity(r, null);
} break;
......
} ...... } ......
}
这里最后调用ActivityThread类的handleLaunchActivity函数进一步处理。
public final class ActivityThread { ...... private final void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...... Activity a = performLaunchActivity(r, customIntent); if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward); ......
} else {
......
}
} ......
}
这里首先调用performLaunchActivity函数来载入这个Activity类,即Home界面Activity,然后调用它的onCreate函数,最后回到handleLaunchActivity函数时,再调用handleResumeActivity函数来使这个Activity进入Resumed状态,即会调用这个Activity的onResume函数,这是遵循Activity的生命周期的。
public final class ActivityThread { ...... private final Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { ...... ComponentName component = r.intent.getComponent();
...... Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
......
} catch (Exception e) {
......
} try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation); ...... if (activity != null) {
ContextImpl appContext = new ContextImpl();
appContext.init(r.packageInfo, r.token, this);
appContext.setOuterContext(activity);
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mConfiguration);
......
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstance,
r.lastNonConfigurationChildInstances, config); .......
mInstrumentation.callActivityOnCreate(activity, r.state);
......
}
...... mActivities.put(r.token, r); } catch (SuperNotCalledException e) {
...... } catch (Exception e) {
......
} return activity;
} ......
}
这样。就開始运行Home界面的onCreate。
1、至此,Launcher进程Binder子线程池在给主线程发送消息后,又进入睡眠等待状态。onCreate是通过消息机制。在主线程中运行的。
2、System进程又在线程池(主线程和子线程)继续等待了。
消息机制在子线程中循环。
3、Zygote进程等待连接请求,创建新的应用程序进程。
Home界面的启动的更多相关文章
- HTML5移动Web开发(七)——通过界面图标启动Web应用
现在我们要使用手机上某个应用时,通过点击屏幕上的图标就可以运行.但是对基于HTML的Web应用来说,运行起来就比较麻烦了,用户必须先打开浏览器,然后访问想使用的应用程序站点.现在我们想把一个指定的We ...
- 描述Linux系统开机到登陆界面的启动过程(计时2分钟)
简述: 1.开机BIOS自检 2.MBR引导 3.grub引导菜单 4.加载内核kernel 5.启动init进程 6.读取inittab文件,执行rc.sysinit,rc等脚本 7.启动minge ...
- 描述linux系统从开机到登陆界面的启动过程
简述:1.开机BIOS自检2.MBR引导3.grub引导菜单4.加载内核kernel5.启动init进程6.读取inittab文件,执行rc.sysinit,rc等脚本7.启动mingetty,进入系 ...
- Centos7无界面化启动
Centos7无界面启动: 为了减少系统开销,有时候我们需要无图形界面启动linux(centos7) systemctl set-default multi-user.target (关闭图形界面) ...
- Ubuntu16.04的图形化界面无法启动问题
昨晚在 Ubuntu 下试图安装笔记本触控板的驱动的时候,突然 Ubuntu 的图形化界面不见了,尝试了 Ctrl + Alt + F1.F2.F3...无果,又在一些博客的指导下尝试在命令行使用 s ...
- Android 中如何从一个App启动另外一个App(如启动支付界面、启动地图界面、应用商场下载App等场景)
假定两个App,分别是A和B,当A运行某个功能需要启动B,一种是启动B应用,一种直接进入B的某个Activity.搜了很多资料,没有一个完整的.下面就A--Android5.1.1.B--Androi ...
- IOS 通过界面图标启动Web应用 + 全屏应用 + 添加到主屏幕
请注意!!!使用了[全屏模式之后].页面的顶部会空出一大块.而且这并不属于margin,padding,或者定位.就是单纯的空出来非常难调试.其实坑就是这里 在 iPhone「添加到主屏幕」时显示自定 ...
- Android界面组件的四种启动方式
Android界面组件启动有四种方式 standard,singleTop,singleTask,singleInstance. standard:每次调用都会都会产生新的组件. singletop: ...
- iOS-APP中添加启动界面
iOS,非常高兴的又回到了这个领域.纠结的就业之路...找工作的这段时间里,原本以为是iOS的游戏开发,却一直只有后台的offer,到Android,最后正式上班的时候却被告知调到了iOS开发,当然不 ...
随机推荐
- [NOI.AC#33]bst 线段树
链接 区间修改,完全二叉树,这引导我们把这棵树看成一棵线段树 .线段树的每一个节点相当于这棵二叉树的节点, 对于区间交换操作,我们对二叉树的每一层从上到下分别考虑,找到L,R在第i层对应的节点修改 这 ...
- vue 刷新当前页面的方式
1.使用window.location.href window.location.replace() window.location.reload() 会出现空白,体验不是很好 2.先进入一个空路由, ...
- BZOJ3620: 似乎在梦中见过的样子(KMP)
Description “Madoka,不要相信 QB!”伴随着 Homura 的失望地喊叫,Madoka 与 QB 签订了契约. 这是 Modoka 的一个噩梦,也同时是上个轮回中所发生的事.为了使 ...
- 如何使用maven 打包源代码呢?
如何使用maven 打包源代码呢? http://hw1287789687.iteye.com/blog/1943157
- canvas.toDataURL() gives “Security Error” in IE 11
http://stackoverflow.com/questions/30101143/canvas-todataurl-gives-security-error-in-ie-11
- [转载]Google Java Style 中文版
转自:http://www.blogjava.net/zh-weir/archive/2014/02/08/409608.html Google Java Style 中文版 基于官方文档20 ...
- 限制tomcat仅响应本机请求(转)
http://blog.bbzhh.com/index.php/archives/135.html 在VPS上搭建了nginx和tomcat应用,想通过nginx来反向代理127.0.0.1:8080 ...
- 51Nod——N1284 2 3 5 7的倍数
https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1284 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 ...
- 洛谷 P1601 A+B Problem(高精)
P1601 A+B Problem(高精) 题目背景 无 题目描述 高精度加法,x相当于a+b problem,[b][color=red]不用考虑负数[/color][/b] 输入输出格式 输入格式 ...
- 洛谷 P2807 三角形计数
P2807 三角形计数 题目背景 三角形计数(triangle) 递推 题目描述 把大三角形的每条边n等分,将对应的等分点连接起来(连接线分别平行于三条边),这样一共会有多少三角形呢?编程来解决这个问 ...