我手机总出现选择应用 Attachqtreewidget 选择iBingoSecurity 是什么意思

华夏通手机核心软件iBingosecurity是病毒吗?_百度知道android开发中遇到的问题汇总【九】
244.http请求的url含有中字符时,需要Uri编码。Uri.encoder()
245.使用androidstudio时,不知道什么原因svn不见了
Studio missing Subversion plugin
Please make sure that the &SubversionIntegration& plugin is enabled in Preferences & Plugins
246.Error:Execution failed for task &:app:dexDebug&.& com.mon.process.ProcessException: org.gradle.process.internal.ExecException: Process &command &/home/xxx/tools/android/jdk1.7.0_71/bin/java& finished with non-zero exit value 2
检查下是否多次引用同一个jar包
1. module下jar包版本不同
同一个module 在libs中包含乐.jar,而在src下又把相应的source页加入了
gradle中是否重复编译,
已经加了compile fileTree(include: [&*.jar&], dir: &libs&)
然而在下面又加一句compile files(&libs/xxx.jar&)
246.android handler的警告Handler Class Should be Static or Leaks Occur
在使用Handler更新UI的时候public class SampleActivity extends Activity {
private final Handler mLeakyHandler = new Handler() {
public void handleMessage(Message msg) {
}会包上述warning 会导致内存泄露
原因在于匿名内部类handler持有activity的引用,当activity finish后 handler还没有处理完,导致activity的view和resource资源不能得到释放,导致内存泄露
针对这个问题google官方给出了正确的做法
通过静态内部类 包含activity的弱引用来处理。
public class SampleActivity extends Activity {
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
private static class MyHandler extends Handler {
private final WeakReference mA
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference(activity);
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
private final MyHandler mHandler = new MyHandler(this);
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are &static&.
private static final Runnable sRunnable = new Runnable() {
public void run() { }
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 60 * 10 * 1000);
// Go back to the previous Activity.
247.androidstudio不同tab切换 ctrl+tab
248.androidstudio 如何自动import用到的类或接口?
For Windows/, you can go to File -& Settings -& Editor -& General -& Auto Import -&
and make the following changes:
change Insert imports on paste value to All
markAdd unambigious imports on the fly option as checked
On a Mac, do the same thing in Android Studio -& Preferences
249.Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/home/cenuser/android/android-ndk-r7b/build/core/build-local.mk:130: *** Android NDK: Aborting
cd到jni目录。或者 ndk-build -C your_project_path
250 .Why do I want to avoid non-default constructors in fragments? fragment设置参数正确的做法
Make a bundle object and insert your data (in this example your Category object). Be careful, you can't pass this object directly into the bundle, unless it's serializable. I think it's better to build your object in the fragment, and put only an id or something else into bundle. This is the code to create and attach a bundle:
Bundle args = new Bundle();
args.putLong(&key&, value);
yourFragment.setArguments(args);
After that, in your fragment access data:
Type value = getArguments().getType(&key&);
That's all.
251. ubuntu下删除.svn的方法
find -type d -name '.svn' -exec rm -rfv {} \;
参考 http://blog.csdn.net/zhaoyu7777777/article/details/9445717
252. Fatal : Could not read from remote repository.
git配置使用,已经把公钥发给发给服务端,在终端命令行也是可以正常的pull push,但是在androidstudio push或者pull的时候确出现上述错误
setting && Version Control &&Git ,In the SSH executable dropdown, choose Native
253. ubuntu获取证书指纹的命令
keytool -list -keystore xxx.keystore
eg:查看debug.keystore
keytool -list -keystore ~/.android/debug.keystore
254. mac 命令行安装软件
通过brew安装,相当于ubuntu中得apt-get
首先安装brew
curl -LsSf
| sudo tar xvz -C/usr/local &strip 1
然后就可以使用brew安装软件了
比如 使用brew安装软件 brew install wget
255.代码混淆时 报如下错误 Error:Execution failed for task &:app:proguarxxxRelease&.
java.io.IOException: Can&t read [/libs/xxx.jar] (No such file or directory)
解答 proguard-android.txt文件中不用在指定 -injars, -outjars, or -libraryjars or libs.
The Android Gradle plugin already specifies all input and output for you, so you must not specify -injars, -outjars, or -libraryjars.
Moreover, the file proguard-android.txt in the Android SDK specifies all generic Android settings for you, so you shouldn&t specify them again.
Essentially, your file proguard-rules.txt can be empty, except for any application-specific settings to make sure any reflection continues to work
256.Android中如何设置RadioButton在文字的右边,图标在左边
解决方法 :
android:button=&@null&这条语句将原来的RadioButton图标给隐藏起来。
android:drawableRight=&@android:drawable/btn_radio&这条语句
257.java报&非法字符: \65279 &错误的解决方法
众所周知,在跨程序的工程中,统一编码是至关重要的,而目前最普遍的则是统一采用&utf8&编码方案。
但是在采用utf8方案的时候,请注意编辑器的自作聪明。
比如editplus。
原因就在于某些编辑器会往utf8文件中添加utf8标记(editplus称其为签名),它会在文件开始的地方插入三个不可见的字符(0xEF 0xBB 0xBF,即BOM),它的表示的是 Unicode 标记(BOM)。
258.手机root后 还会出现下述情况Android: adb: copy file to /system (Permission denied)
解决方式,需要remount /system
mount -o remount,rw /system
259.androidstudio 手动添加assets文件 路径在哪
XXX\src\main\assets
260.android双击back退出
public class MainActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toast = Toast.makeText(getApplicationContext(), &确定退出?&, 0);
public void onBackPressed() {
quitToast();
private void quitToast() {
if(null == toast.getView().getParent()){
toast.show();
System.exit(0);
protected void onCreate(Bundle savedInstanceState) {
toast = Toast.makeText(this, &再按一次退出应用&, Toast.LENGTH_SHORT);
toast.setGravity(Gravity.BOTTOM, 0, ConversionUtil.dip2px(this, 150));
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
if(toast!=null){
toast.cancel();
super.onBackPressed();
this.doubleBackToExitPressedOnce =
toast.show();
new Handler().postDelayed(new Runnable() {
public void run() {
doubleBackToExitPressedOnce=
261.anroid几个很不错的快捷键
Ctrl+Shift+Alt+T 重构代码 change name Ctrl+I 水平分屏显示【需要在keymap中搜索split 设置move right的快捷键】 shift+alt+L 变量生成 ctrl+shift+v
262.在旧项目中引入android materialdesign 时 出现如下问题
android.view.InflateException: Binary XML file line #17: Error inflating class android.support.design.internal.NavigationMenuView
Caused by: java.lang.reflect.InvocationTargetException
Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f0100c5 a=-1}
You need to use a Theme.AppCompat theme (or descendant) with this activity.
解决方法 :使用NavigationMenuView的Activity【一般都是mainActivity】继承自AppCompatActivity,并且修改AndroidManifest.xml中对应activity的theme,使用继承自@style/Theme.AppCompat的主题。
262.How to get key and value of HashMap in java
public class AccessKeyValueOfHashMap {
public static void main(String[] args) {
// Create a Empty HashMap
HashMap obHashMap = new HashMap();
// Put values in hash map
obHashMap.put(&AB&, &1&);
obHashMap.put(&EF&, &2&);
obHashMap.put(&Gh&, &3&);
obHashMap.put(&CD&, &4&);
//Store entry (Key/Value)of HashMap in set
Set mapSet = (Set) obHashMap.entrySet();
//Create iterator on Set
Iterator mapIterator = mapSet.iterator();
System.out.println(&Display the key/value of HashMap.&);
while (mapIterator.hasNext()) {
Map.Entry mapEntry = (Map.Entry) mapIterator.next();
// getKey Method of HashMap access a key of map
String keyValue = (String) mapEntry.getKey();
//getValue method returns corresponding key's value
String value = (String) mapEntry.getValue();
System.out.println(&Key : & + keyValue + &= Value : & + value);
263. 设置键盘回车为发送建
android:imeOptions=&actionSend&
android:inputType=&text&
264. editText 取消背景格式 取消下划线等自带样式
去掉下划线只需把背景设置成为&@null&,
如果想设为其他样式也是设置背景
265. How to build an .so binary for a device with a 64-bit CPU?
latest version of the NDK (right now it's r10e)
Application.mk
APP_ABI := armeabi arm64-v8a armeabi-v7a x86 mips
266. Android NDK for x86_64 has no reference for bcopy and index
You can fix this cleanly with a single line in Application.mk (docs):
APP_CFLAGS += -DSTDC_HEADERS
267.Error:Execution failed for task &:xxx:processDebugManifest&. & Manifest merger failed : uses-sdk element cannot have a &tools:node& attribute
This has been updated to reflect the release of API 21, Lollipop. Be sure to download the latest SDK.
In one of my modules I had the following in build.gradle:
dependencies {
compile 'com.android.support:support-v4:+'
Changing this to
dependencies {
// do not use dynamic updating.
compile 'com.android.support:support-v4:21.0.0'
fixed the issue.
268.Error:(1, 1) A problem occurred evaluating project &xxx&. & Could not create plugin of type &LibraryPlugin&.
修改了build.gradle中的gradle
也要修改gradle-wrapper.properties
build.gradle
dependencies {
classpath 'com.android.tools.build:gradle:1.2.3'
gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
269.androidstudio Building Apps with Over 65K Methods
compileSdkVersion 21
buildToolsVersion &21.1.0&
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
// Enabling multidex support.
multiDexEnabled true
dependencies {
compile 'com.android.support:multidex:1.0.0'
270.Caused by: java.lang.NoClassDefFoundError: android.support.v4.util.Pools$SimplePool
271.Caused by: java.lang.NoSuchMethodException: [class android.content.Context, interface android.util.AttributeSet]
272.java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{423a4c60 position=4 id=-1, oldPos=1, pLpos:1 scrap tmpDetached not recyclable(1) no parent}
273.Failure [INSTALL_PARSE_FAILED_MANIFEST_MALFORMED]
I was having this error because i had capital letters in my package name like this
Com.Example.packagename
after i had changed it to something like
com.example.packagename
it was solved
273.解决异常Circular dependencies cannot exist in RelativeLayout
RelativeLayout中存在循环的相关
274.java.lang.ClassNotFoundException 使用MultiDex 后,运行时发现有些crash或者有些类无法调用 报NoClassDefFound error
首先正确使用 google的multipartdex
修改Gradle,导入&com.android.support:multidex:1.0.0&,打开multiDexE
compileSdkVersion 21
buildToolsVersion &21.1.0&
defaultConfig {
minSdkVersion 14
targetSdkVersion 21
// Enabling multidex support.
multiDexEnabled true
dependencies {
compile 'com.android.support:multidex:1.0.0'
修改Application.两种方法:
1) 直接把Application替换成MultiDexApplication
2) 在原来的Application中修改调用MultiDex.install(this);
public class HelloMultiDexApplication extends Application {
public void onCreate() {
super.onCreate();
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
如果做了上面处理,依旧NoClassDefFound error 通过如下方式处理:
一些在二级Dex加载之前,可能会被调用到的类(比如静态变量的类),需要放在主Dex中.否则会ClassNotFoundError.
通过修改Gradle,可以显式的把一些类放在Main Dex中.
275.Linux 32 Bit Libraries
sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 lib32z1
276.Android Material Design TabLayout.when more than screen width scroll when less than screen width fill
Android TabLayout,当tab总宽度少于一屏时候,扩展为屏幕宽度展示.当tab总宽度大于一屏时,滚动显示
Tab gravity only effects MODE_FIXED.
One possible solution is to set your layout_width to wrap_content and layout_gravity to center_horizontal:
If the tabs are smaller than the screen width, the TabLayout itself will also be smaller and it will be centered because of the gravity. If the tabs are bigger than the screen width, the TabLayout will match the screen width and scrolling will activate.
277. android多渠道打包
目前采用的方案是,在AndroidManifest.xml文件中配置
在app的build.gradle文件中配置
//用于生成不同渠道号
productFlavors {
wandoujia {}
yingyongbao{}
productFlavors.all {
flavor -& flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
这样编译时会生成对应的渠道包apk.现在问题来了,如果有几十个渠道,会生成对应几十个apk包.打包编译一个apk一般需要1分钟左右(和电脑配置有关).那么打包几十个要几十分钟的时间.确实挺费时间的.那么有没有好的方式呐?
当然是有的
我们可以采用如下方案处理.通过文件配置只需要生成一个apk包
此种方法是需要创建文件的。
我们在写完我们的代码之后,在app/src下面,分别创建和main同级目录的文件夹umeng, wandoujia, yingyongbao,这三个文件夹里面都各只有一个AndroidManifest.xml文件,文件只需要如下:
[plain] view plain copy 在CODE上查看代码片派生到我的代码片
注意,上面的value的值要和你的渠道名所对应。比如wandoujia里面要对应为你豌豆荚上的渠道名(如WANDOUJAI)。
然后在你的build.gradle的android{}节点里面,添加productFlavors节点,代码如下:
[plain] view plain copy 在CODE上查看代码片派生到我的代码片
// 这里是你的其他配置
productFlavors{
wandoujai {
yingyongbao{
// 你的其他配置
注意这里的flavors的名字要和你的文件夹的名字对应。这样配置之后,构建的就是多渠道的APK了。
278 Tcpdump抓包
有些模拟器比如genymotion自带了tcpdump,如果没有的话,需要tcpdump:
把tcpdump push到/data/local下,抓包命令:
279 查看签名
很多开发者服务都需要绑定签名信息,用下面的命令可以查看签名:
keytool -list -v -keystore release.jks
281 一行居中,多行居左的TextView
这个一般用于提示信息对话框,如果文字是一行就居中,多行就居左。
在TextView外套一层wrap_content的ViewGroup即可简单实现:
282 setCompoundDrawablesWithIntrinsicBounds()
网上一大堆setCompoundDrawables()方法无效不显示的问题,然后解决方法是setBounds,需要计算大小&
不用这么麻烦,用setCompoundDrawablesWithIntrinsicBounds()这个方法最简单!
282 更新媒体库文件
以前做ROM的时候经常碰到一些第三方软件(某音乐APP)下载了新文件或删除文件之后,但是媒体库并没有更新,因为这个是需要第三方软件主动触发。
283 Monkey参数
大家都知道,跑monkey的参数设置有一些要注意的地方,比如太快了不行不切实际,太慢了也不行等等,这里给出一个参考:
一边跑monkey,一遍抓log吧。
284 强大的dumpsys
dumpsys可以查看系统服务和状态,非常强大,可通过如下查看所有支持的子命令:
这里列举几个稍微常用的:
vczlv+K74dTayta7+sb0tq+jrFNEv6iy5bDOtcTH6b/2z8K9+NDQyKvFzMmow+ijrLK7ysfKtcqxtcS2+MfStPq827HIvc+086Osy/nS1LWluPbOxLz+tcTLotDCutzT0LHY0qqhozwvcD4NCjxwPteiWzI3OC0yODTAtNS009pdoaE8YnIgLz4NCjxhIGhyZWY9"https://mp./s?__biz=MzA4MjU5NTY0NA==&mid=&idx=1&sn=8bbbba7692dca68cdda2212dec4d86c0&scene=1&srcid=0320gXPloap70ixGeYnNUaAW&key=710a5dfe638b34e38edcf6f10b927c7eb5b60bc342db482d2a&ascene=0&uin=MTYzMjY2MTE1&devicetype=iMac+MacBookPro10%2C1+OSX+OSX+10.11.3+build%&version=&pass_ticket=pvdhfR4lRer%2FtYDsP5cnFux5OK0GM%2FUQMgt5TOvHlpQ%3D">你应该知道的那些Android小经验
285. 在布局文件时,在xml可视化文件中看到效果,而又不影响最终展示.可以通过tools来协助
&code class=&language-java hljs &&&!--{cke_protected}{C}%3C!%2D%2D%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%2D%2D%3E--&
&relativelayout xmlns:android=&/apk/res/android& xmlns:tools=&/tools& android:id=&@+id/rootView& android:layout_width=&match_parent& android:layout_height=&match_parent& android:gravity=&center&&
&progressbar android:id=&@+id/progress_loading& android:layout_width=&75dp& android:layout_height=&60dp&&
&textview android:id=&@+id/tv_reload& android:layout_width=&wrap_content& android:layout_height=&wrap_content& android:background=&@android:color/transparent& android:src=&@drawable/refresh_big& android:scaletype=&centerInside& android:visibility=&gone& tools:text=&点我,重新加载& tools:visibility=&visible&&
&/textview&&/progressbar&&/relativelayout&
加填充xml文件时,TextView是隐藏的,但又想在xml中直观的看到它显示后的整体效果.借助xmlns:tools=&/tools& 完美实现.
286. android studio对于错误拼写/不识别的英文单词,给予波浪提示。
Spellchecker inspection helps locate typos and misspelling in your code, comments and literals, and fix them in one click
选中单词,单击鼠标右键 spelling
Save &xxx& to dictionary..
287. Warning: Use &&insteadof&.&forinnerclasses(orunlylowercaselettersinpackagenames);replace.with
Package names are written in all lower case to avoid conflict with the names of classes or interfaces.
包名小写,避免和类名或接口名冲突
288. JNI undefined reference to `__android_log_print&
defaultConfig {
moduleName &your_module_name&
ldLibs &log&
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'APP启动过程 - 博客频道 - CSDN.NET
分类:android面试Android/第三方库 源码解析
【原文地址 】
It's right time to learn Android's Framework !
一个App是怎么启动起来的?App的程序入口到底是哪里?Launcher到底是什么神奇的东西?听说还有个AMS的东西,它是做什么的?Binder是什么?他是如何进行IPC通信的?Activity生命周期到底是什么时候调用的?被谁调用的?等等...
你是不是还有很多类似的疑问一直没有解决?没关系,这篇文章将结合源码以及大量的优秀文章,站在巨人的肩膀上,更加通俗的来试着解释一些问题。但是毕竟源码繁多、经验有限,文中不免会出现一些纰漏甚至是错误,还恳请大家指出,互相学习。
了解从手机开机第一个zygote进程创建,到点击桌面上的图标,进入一个App的完整流程,并且从源码的角度了解到一个Activity的生命周期是怎么回事了解到ActivityManagerServices(即AMS)、ActivityStack、ActivityThread、Instrumentation等Android framework中非常重要的基础类的作用,及相互间的关系了解AMS与ActivityThread之间利用Binder进行IPC通信的过程,了解AMS和ActivityThread在控制Activity生命周期起到的作用和相互之间的配合了解与Activity相关的framework层的其他琐碎问题
这篇文章我决定采用一问一答的方式进行。
其实在这之前,我试过把每个流程的代码调用过程,用粘贴源代码的方式写在文章里,但是写完一部分之后,发现由于代码量太大,整篇文章和老太太的裹脚布一样——又臭又长,虽然每个重要的操作可以显示出详细调用过程,但是太关注于细节反而导致从整体上不能很好的把握。所以在原来的基础之上进行了修改,对关键的几个步骤进行重点介绍,力求语言简洁,重点突出,从而让大家在更高的层次上对framework层有个认识,然后结合后面我给出的参考资料,大家就可以更加快速,更加高效的了解这一块的整体架构。
主要对象功能介绍
我们下面的文章将围绕着这几个类进行介绍。可能你第一次看的时候,印象不深,不过没关系,当你跟随者我读完这篇文章的时候,我会在最后再次列出这些对象的功能,相信那时候你会对这些类更加的熟悉和深刻。
ActivityManagerServices,简称AMS,服务端对象,负责系统中所有Activity的生命周期ActivityThread,App的真正入口。当开启App之后,会调用main()开始运行,开启消息循环队列,这就是传说中的UI线程或者叫主线程。与ActivityManagerServices配合,一起完成Activity的管理工作ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯。ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的。Instrumentation,每一个应用程序只有一个Instrumentation对象,每个Activity内都有一个对该对象的引用。Instrumentation可以理解为应用进程的管家,ActivityThread要创建或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作。ActivityStack,Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。ActivityRecord,ActivityStack的管理对象,每个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其他的管理信息。其实就是服务器端的Activity对象的映像。TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。如果你清楚Activity的4种launchMode,那么对这个概念应该不陌生。
主要流程介绍
下面将按照App启动过程的先后顺序,一问一答,来解释一些事情。
让我们开始吧!
zygote是什么?有什么作用?
首先,你觉得这个单词眼熟不?当你的程序Crash的时候,打印的红色log下面通常带有这一个单词。
zygote意为“受精卵“。Android是基于Linux系统的,而在Linux中,所有的进程都是由init进程直接或者是间接fork出来的,zygote进程也不例外。
在Android系统里面,zygote是一个进程的名字。Android是基于Linux System的,当你的手机开机的时候,Linux的内核加载完成之后就会启动一个叫“init“的进程。在Linux System里面,所有的进程都是由init进程fork出来的,我们的zygote进程也不例外。
我们都知道,每一个App其实都是
一个单独的dalvik虚拟机一个单独的进程
所以当系统里面的第一个zygote进程运行之后,在这之后再开启App,就相当于开启一个新的进程。而为了实现资源共用和更快的启动速度,Android系统开启新进程的方式,是通过fork第一个zygote进程实现的。所以说,除了第一个zygote进程,其他应用所在的进程都是zygote的子进程,这下你明白为什么这个进程叫“受精卵”了吧?因为就像是一个受精卵一样,它能快速的分裂,并且产生遗传物质一样的细胞!
SystemServer是什么?有什么作用?它与zygote的关系是什么?
首先我要告诉你的是,SystemServer也是一个进程,而且是由zygote进程fork出来的。
知道了SystemServer的本质,我们对它就不算太陌生了,这个进程是Android Framework里面两大非常重要的进程之一——另外一个进程就是上面的zygote进程。
为什么说SystemServer非常重要呢?因为系统里面重要的服务都是在这个进程里面开启的,比如
ActivityManagerService、PackageManagerService、WindowManagerService等等,看着是不是都挺眼熟的?
那么这些系统服务是怎么开启起来的呢?
在zygote开启的时候,会调用ZygoteInit.main()进行初始化
public static void main(String argv[]) {
...ignore some code...
boolean startSystemServer = false;
for (int i = 1; i & argv. i++) {
if (&start-system-server&.equals(argv[i])) {
startSystemServer = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
throw new RuntimeException(&Unknown command line argument: & + argv[i]);
...ignore some code...
if (startSystemServer) {
startSystemServer(abiList, socketName);
...ignore some code...
我们看下startSystemServer()做了些什么
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
...ignore some code...
String args[] = {
&--setuid=1000&,
&--setgid=1000&,
&--setgroups=03,06,09,32,03,&,
&--capabilities=& + capabilities + &,& + capabilities,
&--runtime-init&,
&--nice-name=system_server&,
&com.android.server.SystemServer&,
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
handleSystemServerProcess(parsedArgs);
return true;
ActivityManagerService是什么?什么时候初始化的?有什么作用?
ActivityManagerService,简称AMS,服务端对象,负责系统中所有Activity的生命周期。
ActivityManagerService进行初始化的时机很明确,就是在SystemServer进程开启的时候,就会初始化ActivityManagerService。从下面的代码中可以看到
public final class SystemServer {
public static void main(String[] args) {
new SystemServer().run();
public SystemServer() {
mFactoryTestMode = FactoryTest.getMode();
private void run() {
...ignore some code...
System.loadLibrary(&android_servers&);
nativeInit();
createSystemContext();
mSystemServiceManager = new SystemServiceManager(mSystemContext);
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e(&System&, &******************************************&);
Slog.e(&System&, &************ Failure starting system services&, ex);
...ignore some code...
private void createSystemContext() {
ActivityThread activityThread = ActivityThread.systemMain();
mSystemContext = activityThread.getSystemContext();
mSystemContext.setTheme(android.R.style.Theme_DeviceDefault_Light_DarkActionBar);
private void startBootstrapServices() {
...ignore some code...
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
mActivityManagerService.initPowerManagement();
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
mPackageManagerService = PackageManagerService.main(mSystemContext, mInstaller,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
...ignore some code...
经过上面这些步骤,我们的ActivityManagerService对象已经创建好了,并且完成了成员变量初始化。而且在这之前,调用createSystemContext()创建系统上下文的时候,也已经完成了mSystemContext和ActivityThread的创建。注意,这是系统进程开启时的流程,在这之后,会开启系统的Launcher程序,完成系统界面的加载与显示。
你是否会好奇,我为什么说AMS是服务端对象?下面我给你介绍下Android系统里面的服务器和客户端的概念。
其实服务器客户端的概念不仅仅存在于Web开发中,在Android的框架设计中,使用的也是这一种模式。服务器端指的就是所有App共用的系统服务,比如我们这里提到的ActivityManagerService,和前面提到的PackageManagerService、WindowManagerService等等,这些基础的系统服务是被所有的App公用的,当某个App想实现某个操作的时候,要告诉这些系统服务,比如你想打开一个App,那么我们知道了包名和MainActivity类名之后就可以打开
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
ComponentName cn = new ComponentName(packageName, className);
intent.setComponent(cn);
startActivity(intent);
但是,我们的App通过调用startActivity()并不能直接打开另外一个App,这个方法会通过一系列的调用,最后还是告诉AMS说:“我要打开这个App,我知道他的住址和名字,你帮我打开吧!”所以是AMS来通知zygote进程来fork一个新进程,来开启我们的目标App的。这就像是浏览器想要打开一个超链接一样,浏览器把网页地址发送给服务器,然后还是服务器把需要的资源文件发送给客户端的。
知道了Android Framework的客户端服务器架构之后,我们还需要了解一件事情,那就是我们的App和AMS(SystemServer进程)还有zygote进程分属于三个独立的进程,他们之间如何通信呢?
App与AMS通过Binder进行IPC通信,AMS(SystemServer进程)与zygote通过Socket进行IPC通信。
那么AMS有什么用呢?在前面我们知道了,如果想打开一个App的话,需要AMS去通知zygote进程,除此之外,其实所有的Activity的开启、暂停、关闭都需要AMS来控制,所以我们说,AMS负责系统中所有Activity的生命周期。
在Android系统中,任何一个Activity的启动都是由AMS和应用程序进程(主要是ActivityThread)相互配合来完成的。AMS服务统一调度系统中所有进程的Activity启动,而每个Activity的启动过程则由其所属的进程具体来完成。
这样说你可能还是觉得比较抽象,没关系,下面有一部分是专门来介绍AMS与ActivityThread如何一起合作控制Activity的生命周期的。
Launcher是什么?什么时候启动的?
当我们点击手机桌面上的图标的时候,App就由Launcher开始启动了。但是,你有没有思考过Launcher到底是一个什么东西?
Launcher本质上也是一个应用程序,和我们的App一样,也是继承自Activity
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,那么我们的开发经验在这里就仍然适用,比如,我们点击图标的时候,是怎么开启的应用呢?如果让你,你怎么做这个功能呢?捕捉图标点击事件,然后startActivity()发送对应的Intent请求呗!是的,Launcher也是这么做的,就是这么easy!
那么到底是处理的哪个对象的点击事件呢?既然Launcher是App,并且有界面,那么肯定有布局文件呀,是的,我找到了布局文件launcher.xml
xmlns:android=&/apk/res/android&
xmlns:launcher=&/apk/res/com.android.launcher&
android:id=&@+id/launcher&&
android:id=&@+id/drag_layer&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:fitsSystemWindows=&true&&
android:id=&@+id/dock_divider&
layout=&@layout/workspace_divider&
android:layout_marginBottom=&@dimen/button_bar_height&
android:layout_gravity=&bottom& /&
android:id=&@+id/paged_view_indicator&
layout=&@layout/scroll_indicator&
android:layout_gravity=&bottom&
android:layout_marginBottom=&@dimen/button_bar_height& /&
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/workspace_divider_padding_left&
launcher:scrollIndicatorPaddingRight=&@dimen/workspace_divider_padding_right&&
android:id=&@+id/cell1& layout=&@layout/workspace_screen& /&
android:id=&@+id/cell2& layout=&@layout/workspace_screen& /&
android:id=&@+id/cell3& layout=&@layout/workspace_screen& /&
android:id=&@+id/cell4& layout=&@layout/workspace_screen& /&
android:id=&@+id/cell5& layout=&@layout/workspace_screen& /&
...ignore some code...
为了方便查看,我删除了很多代码,从上面这些我们应该可以看出一些东西来:Launcher大量使用&include/&标签来实现界面的复用,而且定义了很多的自定义控件实现界面效果,dock_divider从布局的参数声明上可以猜出,是底部操作栏和上面图标布局的分割线,而paged_view_indicator则是页面指示器,和App首次进入的引导页下面的界面引导是一样的道理。当然,我们最关心的是Workspace这个布局,因为注释里面说在这里面包含了5个屏幕的单元格,想必你也猜到了,这个就是在首页存放我们图标的那五个界面(不同的ROM会做不同的DIY,数量不固定)。
接下来,我们应该打开workspace_screen布局,看看里面有什么东东。
workspace_screen.xml
&com.android.launcher2.CellLayout
xmlns:android=&/apk/res/android&
xmlns:launcher=&/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& /&
里面就一个CellLayout,也是一个自定义布局,那么我们就可以猜到了,既然可以存放图标,那么这个自定义的布局很有可能是继承自ViewGroup或者是其子类,实际上,CellLayout确实是继承自ViewGroup。在CellLayout里面,只放了一个子View,那就是ShortcutAndWidgetContainer。从名字也可以看出来,ShortcutAndWidgetContainer这个类就是用来存放快捷图标和__Widget小部件__的,那么里面放的是什么对象呢?
在桌面上的图标,使用的是BubbleTextView对象,这个对象在TextView的基础之上,添加了一些特效,比如你长按移动图标的时候,图标位置会出现一个背景(不同版本的效果不同),所以我们找到BubbleTextView对象的点击事件,就可以找到Launcher如何开启一个App了。
除了在桌面上有图标之外,在程序列表中点击图标,也可以开启对应的程序。这里的图标使用的不是BubbleTextView对象,而是PagedViewIcon对象,我们如果找到它的点击事件,就也可以找到Launcher如何开启一个App。
其实说这么多,和今天的主题隔着十万八千里,上面这些东西,你有兴趣就看,没兴趣就直接跳过,不知道不影响这篇文章阅读。
BubbleTextView的点击事件在哪里呢?我来告诉你:在Launcher.onClick(View v)里面。
public void onClick(View v) {
...ignore some code...
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
final Intent intent = ((ShortcutInfo) tag).
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)
mWaitingForResume.setStayPressed(true);
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
FolderIcon fi = (FolderIcon)
handleFolderClick(fi);
} else if (v == mAllAppsButton) {
...ignore some code...
从上面的代码我们可以看到,在桌面上点击快捷图标的时候,会调用
startActivitySafely(v, intent, tag)
那么从程序列表界面,点击图标的时候会发生什么呢?实际上,程序列表界面使用的是AppsCustomizePagedView对象,所以我在这个类里面找到了onClick(View v)。
com.android.launcher2.AppsCustomizePagedView.java
public class AppsCustomizePagedView extends PagedViewWithDraggableItems implements
View.OnClickListener, View.OnKeyListener, DragSource,
PagedViewIcon.PressedCallback, PagedViewWidget.ShortPressListener,
LauncherTransitionable {
public void onClick(View v) {
...ignore some code...
if (v instanceof PagedViewIcon) {
mLauncher.updateWallpaperVisibility(true);
mLauncher.startActivitySafely(v, appInfo.intent, appInfo);
} else if (v instanceof PagedViewWidget) {
...ignore some code..
可以看到,调用的是
.startActivitySafely(, .intent, );
和上面一样!这叫什么?这叫殊途同归!
所以咱们现在又明白了一件事情:不管从哪里点击图标,调用的都是Launcher.startActivitySafely()。
下面我们就可以一步步的来看一下Launcher.startActivitySafely()到底做了什么事情。
boolean startActivitySafely(View v, Intent intent, Object tag) {
boolean success = false;
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);
调用了startActivity(v, intent, tag)
boolean startActivity(View v, Intent intent, Object tag) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
boolean useLaunchAnimation = (v != null) &&
!intent.hasExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION);
if (useLaunchAnimation) {
if (user == null || user.equals(android.os.Process.myUserHandle())) {
startActivity(intent, opts.toBundle());
launcherApps.startMainActivity(intent.getComponent(), user,
intent.getSourceBounds(),
opts.toBundle());
if (user == null || user.equals(android.os.Process.myUserHandle())) {
startActivity(intent);
launcherApps.startMainActivity(intent.getComponent(), user,
intent.getSourceBounds(), null);
return true;
} catch (SecurityException e) {
return false;
这里会调用Activity.startActivity(intent, opts.toBundle()),这个方法熟悉吗?这就是我们经常用到的Activity.startActivity(Intent)的重载函数。而且由于设置了
.addFlags(.FLAG_ACTIVITY_NEW_TASK);
所以这个Activity会添加到一个新的Task栈中,而且,startActivity()调用的其实是startActivityForResult()这个方法。
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
startActivityForResult(intent, -1);
所以我们现在明确了,Launcher中开启一个App,其实和我们在Activity中直接startActivity()基本一样,都是调用了Activity.startActivityForResult()。
Instrumentation是什么?和ActivityThread是什么关系?
还记得前面说过的Instrumentation对象吗?每个Activity都持有Instrumentation对象的一个引用,但是整个进程只会存在一个Instrumentation对象。当startActivityForResult()调用之后,实际上还是调用了mInstrumentation.execStartActivity()
public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
if (mParent == null) {
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());
...ignore some code...
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
mParent.startActivityFromChild(this, intent, requestCode);
...ignore some code...
下面是mInstrumentation.execStartActivity()的实现
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextT
...ignore some code...
intent.migrateExtraStreamToClipData();
intent.prepareToLeaveProcess();
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) {
return null;
所以当我们在程序中调用startActivity()的 时候,实际上调用的是Instrumentation的相关的方法。
Instrumentation意为“仪器”,我们先看一下这个类里面包含哪些方法吧
我们可以看到,这个类里面的方法大多数和Application和Activity有关,是的,这个类就是完成对Application和Activity初始化和生命周期的工具类。比如说,我单独挑一个callActivityOnCreate()让你看看
public void callActivityOnCreate(Activity activity, Bundle icicle) {
prePerformCreate(activity);
activity.performCreate(icicle);
postPerformCreate(activity);
对activity.performCreate(icicle);这一行代码熟悉吗?这一行里面就调用了传说中的Activity的入口函数onCreate(),不信?接着往下看
Activity.performCreate()
final void performCreate(Bundle icicle) {
onCreate(icicle);
mActivityTransitionState.readState(icicle);
performCreateCommon();
没骗你吧,onCreate在这里调用了吧。但是有一件事情必须说清楚,那就是这个Instrumentation类这么重要,为啥我在开发的过程中,没有发现他的踪迹呢?
是的,Instrumentation这个类很重要,对Activity生命周期方法的调用根本就离不开他,他可以说是一个大管家,但是,这个大管家比较害羞,是一个女的,管内不管外,是老板娘~
那么你可能要问了,老板是谁呀?
老板当然是大名鼎鼎的ActivityThread了!
ActivityThread你都没听说过?那你肯定听说过传说中的UI线程吧?是的,这就是UI线程。我们前面说过,App和AMS是通过Binder传递信息的,那么ActivityThread就是专门与AMS的外交工作的。
AMS说:“ActivityThread,你给我暂停一个Activity!”
ActivityThread就说:“没问题!”然后转身和Instrumentation说:“老婆,AMS让暂停一个Activity,我这里忙着呢,你快去帮我把这事办了把~”
于是,Instrumentation就去把事儿搞定了。
所以说,AMS是董事会,负责指挥和调度的,ActivityThread是老板,虽然说家里的事自己说了算,但是需要听从AMS的指挥,而Instrumentation则是老板娘,负责家里的大事小事,但是一般不抛头露面,听一家之主ActivityThread的安排。
如何理解AMS和ActivityThread之间的Binder通信?
前面我们说到,在调用startActivity()的时候,实际上调用的是
.execStartActivity()
但是到这里还没完呢!里面又调用了下面的方法
.getDefault()
.startActivity
这里的ActivityManagerNative.getDefault返回的就是ActivityManagerService的远程接口,即ActivityManagerProxy。
怎么知道的呢?往下看
public abstract class ActivityManagerNative extends Binder implements IActivityManager
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);
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return new ActivityManagerProxy(obj);
再看ActivityManagerProxy.startActivity(),在这里面做的事情就是IPC通信,利用Binder对象,调用transact(),把所有需要的参数封装成Parcel对象,向AMS发送数据进行通信。
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);
data.writeInt(0);
if (options != null) {
data.writeInt(1);
options.writeToParcel(data, 0);
data.writeInt(0);
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
Binder本质上只是一种底层通信方式,和具体服务没有关系。为了提供具体服务,Server必须提供一套接口函数以便Client通过远程访问使用各种服务。这时通常采用Proxy设计模式:将接口函数定义在一个抽象类中,Server和Client都会以该抽象类为基类实现所有接口函数,所不同的是Server端是真正的功能实现,而Client端是对这些函数远程调用请求的包装。
为了更方便的说明客户端和服务器之间的Binder通信,下面以ActivityManagerServices和他在客户端的代理类ActivityManagerProxy为例。
ActivityManagerServices和ActivityManagerProxy都实现了同一个接口——IActivityManager。
class ActivityManagerProxy implements IActivityManager{}
public final class ActivityManagerService extends ActivityManagerNative{}
public abstract class ActivityManagerNative extends Binder implements IActivityManager{}
虽然都实现了同一个接口,但是代理对象ActivityManagerProxy并不会对这些方法进行真正地实现,ActivityManagerProxy只是通过这种方式对方法的参数进行打包(因为都实现了相同接口,所以可以保证同一个方法有相同的参数,即对要传输给服务器的数据进行打包),真正实现的是ActivityManagerService。
但是这个地方并不是直接由客户端传递给服务器,而是通过Binder驱动进行中转。其实我对Binder驱动并不熟悉,我们就把他当做一个中转站就OK,客户端调用ActivityManagerProxy接口里面的方法,把数据传送给Binder驱动,然后Binder驱动就会把这些东西转发给服务器的ActivityManagerServices,由ActivityManagerServices去真正的实施具体的操作。
但是Binder只能传递数据,并不知道是要调用ActivityManagerServices的哪个方法,所以在数据中会添加方法的唯一标识码,比如前面的startActivity()方法:
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();
...ignore some code...
mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);
reply.readException();
int result = reply.readInt();
reply.recycle();
data.recycle();
上面的START_ACTIVITY_TRANSACTION就是方法标示,data是要传输给Binder驱动的数据,reply则接受操作的返回值。
客户端:ActivityManagerProxy =====&Binder驱动=====& ActivityManagerService:服务器
而且由于继承了同样的公共接口类,ActivityManagerProxy提供了与ActivityManagerService一样的函数原型,使用户感觉不出Server是运行在本地还是远端,从而可以更加方便的调用这些重要的系统服务。
但是!这里Binder通信是单方向的,即从ActivityManagerProxy指向ActivityManagerService的,如果AMS想要通知ActivityThread做一些事情,应该咋办呢?
还是通过Binder通信,不过是换了另外一对,换成了ApplicationThread和ApplicationThreadProxy。
客户端:ApplicationThread &=====Binder驱动&===== ApplicationThreadProxy:服务器
他们也都实现了相同的接口IApplicationThread
private class ApplicationThread extends ApplicationThreadNative {}
public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}
class ApplicationThreadProxy implements IApplicationThread {}
剩下的就不必多说了吧,和前面一样。
AMS接收到客户端的请求之后,会如何开启一个Activity?
OK,至此,点击桌面图标调用startActivity(),终于把数据和要开启Activity的请求发送到了AMS了。说了这么多,其实这些都在一瞬间完成了,下面咱们研究下AMS到底做了什么。
注:前方有高能的方法调用链,如果你现在累了,请先喝杯咖啡或者是上趟厕所休息下
AMS收到startActivity的请求之后,会按照如下的方法链进行调用
调用startActivity()
public final int startActivity(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options) {
return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
resultWho, requestCode, startFlags, profilerInfo, options,
UserHandle.getCallingUserId());
调用startActivityAsUser()
public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
int startFlags, ProfilerInfo profilerInfo, Bundle options, int userId) {
...ignore some code...
return mStackSupervisor.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, options, userId, null, null);
在这里又出现了一个新对象ActivityStackSupervisor,通过这个类可以实现对ActivityStack的部分操作。
final int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, WaitResult outResult, Configuration config,
Bundle options, int userId, IActivityContainer iContainer, TaskRecord inTask) {
...ignore some code...
int res = startActivityLocked(caller, intent, resolvedType, aInfo,
voiceSession, voiceInteractor, resultTo, resultWho,
requestCode, callingPid, callingUid, callingPackage,
realCallingPid, realCallingUid, startFlags, options,
componentSpecified, null, container, inTask);
...ignore some code...
继续调用startActivityLocked()
final int startActivityLocked(IApplicationThread caller,
Intent intent, String resolvedType, ActivityInfo aInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode,
int callingPid, int callingUid, String callingPackage,
int realCallingPid, int realCallingUid, int startFlags, Bundle options,
boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,
TaskRecord inTask) {
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);
if (err & 0) {
notifyActivityDrawnForKeyguard();
调用startActivityUncheckedLocked(),此时要启动的Activity已经通过检验,被认为是一个正当的启动请求。
终于,在这里调用到了ActivityStack的startActivityLocked(ActivityRecord r, boolean newTask,boolean doResume, boolean keepCurTransition, Bundle options)。
ActivityRecord代表的就是要开启的Activity对象,里面分装了很多信息,比如所在的ActivityTask等,如果这是首次打开应用,那么这个Activity会被放到ActivityTask的栈顶,
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
boolean doResume, Bundle options, TaskRecord inTask) {
...ignore some code...
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
...ignore some code...
return ActivityManager.START_SUCCESS;
调用的是ActivityStack.startActivityLocked()
final void startActivityLocked(ActivityRecord r, boolean newTask,
boolean doResume, boolean keepCurTransition, Bundle options) {
TaskRecord rTask = r.
...ignore some code...
TaskRecord task = null;
if (!newTask) {
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx &= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
if (task.getTopActivity() == null) {
if (task == r.task) {
if (!startIt) {
task.addActivityToTop(r);
r.putInHistory();
mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
(r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0,
r.userId, r.info.configChanges, task.voiceSession != null,
r.mLaunchTaskBehind);
if (VALIDATE_TOKENS) {
validateAppTokensLocked();
ActivityOptions.abort(options);
} else if (task.numFullscreen & 0) {
startIt = false;
...ignore some code...
task.addActivityToTop(r);
task.setFrontOfTask();
...ignore some code...
if (doResume) {
mStackSupervisor.resumeTopActivitiesLocked(this, r, options);
靠!这来回折腾什么呢!从ActivityStackSupervisor到ActivityStack,又调回ActivityStackSupervisor,这到底是在折腾什么玩意啊!!!
淡定...淡定...我知道你也在心里骂娘,世界如此美妙,你却如此暴躁,这样不好,不好...
来来来,咱们继续哈,刚才说到哪里了?哦,对,咱们一起看下StackSupervisor.resumeTopActivitiesLocked(this, r, options)
boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
Bundle targetOptions) {
if (targetStack == null) {
targetStack = getFocusedStack();
boolean result = false;
if (isFrontStack(targetStack)) {
result = targetStack.resumeTopActivityLocked(target, targetOptions);
...ignore some code...
我...已无力吐槽了,又调回ActivityStack去了...
ActivityStack.resumeTopActivityLocked()
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
if (inResumeTopActivity) {
return false;
boolean result = false;
inResumeTopActivity = true;
result = resumeTopActivityInnerLocked(prev, options);
} finally {
inResumeTopActivity = false;
咱们坚持住,看一下ActivityStack.resumeTopActivityInnerLocked()到底进行了什么操作
final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
...ignore some code...
ActivityRecord next = topRunningActivityLocked(null);
if (next == null) {
ActivityOptions.abort(options);
if (DEBUG_STATES) Slog.d(TAG, &resumeTopActivityLocked: No more activities go home&);
if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
return isOnHomeDisplay() &&
mStackSupervisor.resumeHomeStackTask(returnTaskType, prev);
if (mResumedActivity != null) {
pausing |= startPausingLocked(userLeaving, false, true, dontWaitForPause);
if (DEBUG_STATES) Slog.d(TAG, &resumeTopActivityLocked: Pausing & + mResumedActivity);
在这个方法里,prev.app为记录启动Lancher进程的ProcessRecord,prev.app.thread为Lancher进程的远程调用接口IApplicationThead,所以可以调用prev.app.thread.schedulePauseActivity,到Lancher进程暂停指定Activity。
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping, boolean resuming,
boolean dontWait) {
if (mPausingActivity != null) {
completePauseLocked(false);
...ignore some code...
if (prev.app != null && prev.app.thread != null)
mService.updateUsageStats(prev, false);
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, dontWait);
} catch (Exception e) {
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
mPausingActivity = null;
mLastPausedActivity = null;
mLastNoHistoryActivity = null;
...ignore some code...
在Lancher进程中消息传递,调用ActivityThread.handlePauseActivity(),最终调用ActivityThread.performPauseActivity()暂停指定Activity。接着通过前面所说的Binder通信,通知AMS已经完成暂停的操作。
.getDefault().activityPaused().
上面这些调用过程非常复杂,源码中各种条件判断让人眼花缭乱,所以说如果你没记住也没关系,你只要记住这个流程,理解了Android在控制Activity生命周期时是如何操作,以及是通过哪几个关键的类进行操作的就可以了,以后遇到相关的问题之道从哪块下手即可,这些过程我虽然也是撸了一遍,但还是记不清。
最后来一张高清无码大图,方便大家记忆:
送给你们的彩蛋
不要使用 startActivityForResult(intent,RESULT_OK)
这是因为startActivity()是这样实现的
public void startActivity(Intent intent, @Nullable Bundle options) {
if (options != null) {
startActivityForResult(intent, -1, options);
startActivityForResult(intent, -1);
public static final int RESULT_OK
startActivityForResult(intent,RESULT_OK) = startActivity()
你不可能从onActivityResult()里面收到任何回调。而这个问题是相当难以被发现的,就是因为这个坑,我工作一年多来第一次加班到9点 (ˇ_ˇ)
一个App的程序入口到底是什么?
是ActivityThread.main()。
整个App的主线程的消息循环是在哪里创建的?
是在ActivityThread初始化的时候,就已经创建消息循环了,所以在主线程里面创建Handler不需要指定Looper,而如果在其他线程使用Handler,则需要单独使用Looper.prepare()和Looper.loop()创建消息循环。
public static void main(String[] args) {
...ignore some code...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, &ActivityThread&));
Looper.loop();
...ignore some code...
Application是在什么时候创建的?onCreate()什么时候调用的?
也是在ActivityThread.main()的时候,再具体点呢,就是在thread.attach(false)的时候。
看你的表情,不信是吧!凯子哥带你溜溜~
我们先看一下ActivityThread.attach()
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread =
if (!system) {
...ignore some code...
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
这里需要关注的就是mgr.attachApplication(mAppThread),这个就会通过Binder调用到AMS里面对应的方法
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), pat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
thread是IApplicationThread,实际上就是ApplicationThread在服务端的代理类ApplicationThreadProxy,然后又通过IPC就会调用到ApplicationThread的对应方法
private class ApplicationThread extends ApplicationThreadNative {
public final void bindApplication(String processName, ApplicationInfo appInfo,
List&ProviderInfo& providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map&String, IBinder& services,
Bundle coreSettings) {
...ignore some code...
AppBindData data = new AppBindData();
data.processName = processN
data.appInfo = appI
data.providers =
data.instrumentationName = instrumentationN
data.instrumentationArgs = instrumentationA
data.instrumentationWatcher = instrumentationW
data.instrumentationUiAutomationConnection = instrumentationUiC
data.debugMode = debugM
data.enableOpenGlTrace = enableOpenGlT
data.restrictedBackupMode = isRestrictedBackupM
data.persistent =
data.config =
patInfo = compatI
data.initProfilerInfo = profilerI
sendMessage(H.BIND_APPLICATION, data);
我们需要关注的其实就是最后的sendMessage(),里面有函数的编号H.BIND_APPLICATION,然后这个Messge会被H这个Handler处理
private class H extends Handler {
...ignore some code...
public static final int BIND_APPLICATION
...ignore some code...
public void handleMessage(Message msg) {
switch (msg.what) {
...ignore some code...
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, &bindApplication&);
AppBindData data = (AppBindData)msg.
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
...ignore some code...
最后就在下面这个方法中,完成了实例化,拨那个企鹅通过mInstrumentation.callApplicationOnCreate实现了onCreate()的调用。
private void handleBindApplication(AppBindData data) {
...ignore some code...
Application app = .makeApplication(data.restrictedBackupMode, null);
mInitialApplication =
...ignore some code...
mInstrumentation.onCreate(data.instrumentationArgs);
catch (Exception e) {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
} finally {
StrictMode.setThreadPolicy(savedPolicy);
<是一个LoadeApk对象。
.makeApplication()
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {
Application app = null;
String appClass = mApplicationInfo.classN
if (forceDefaultAppClass || (appClass == null)) {
appClass = &android.app.Application&;
java.lang.ClassLoader cl = getClassLoader();
if (!mPackageName.equals(&android&)) {
initializeJavaContextClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);
appContext.setOuterContext(app);
} catch (Exception e) {
mActivityThread.mAllApplications.add(app);
mApplication =
if (instrumentation != null) {
instrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
...ignore some code...
所以最后还是通过Instrumentation.makeApplication()实例化的,这个老板娘真的很厉害呀!
static public Application newApplication(Class&?& clazz, Context context)
throws InstantiationException, IllegalAccessException,
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
而且通过反射拿到Application对象之后,直接调用attach(),所以attach()调用是在onCreate()之前的。
下面的这些文章都是这方面比较精品的,希望你抽出时间研究,这可能需要花费很长时间,但是如果你想进阶为中高级开发者,这一步是必须的。
再次感谢下面这些文章的作者的分享精神。
ActivityThread、Instrumentation、AMS
OK,到这里,这篇文章算是告一段落了,我们再回头看看一开始的几个问题,你还困惑吗?
一个App是怎么启动起来的?App的程序入口到底是哪里?Launcher到底是什么神奇的东西?听说还有个AMS的东西,它是做什么的?Binder是什么?他是如何进行IPC通信的?Activity生命周期到底是什么时候调用的?被谁调用的?
再回过头来看看这些类,你还迷惑吗?
ActivityManagerServices,简称AMS,服务端对象,负责系统中所有Activity的生命周期ActivityThread,App的真正入口。当开启App之后,会调用main()开始运行,开启消息循环队列,这就是传说中的UI线程或者叫主线程。与ActivityManagerServices配合,一起完成Activity的管理工作ApplicationThread,用来实现ActivityManagerService与ActivityThread之间的交互。在ActivityManagerService需要管理相关Application中的Activity的生命周期时,通过ApplicationThread的代理对象与ActivityThread通讯。ApplicationThreadProxy,是ApplicationThread在服务器端的代理,负责和客户端的ApplicationThread通讯。AMS就是通过该代理与ActivityThread进行通信的。Instrumentation,每一个应用程序只有一个Instrumentation对象,每个Activity内都有一个对该对象的引用。Instrumentation可以理解为应用进程的管家,ActivityThread要创建或暂停某个Activity时,都需要通过Instrumentation来进行具体的操作。ActivityStack,Activity在AMS的栈管理,用来记录已经启动的Activity的先后关系,状态信息等。通过ActivityStack决定是否需要启动新的进程。ActivityRecord,ActivityStack的管理对象,每个Activity在AMS对应一个ActivityRecord,来记录Activity的状态以及其他的管理信息。其实就是服务器端的Activity对象的映像。TaskRecord,AMS抽象出来的一个“任务”的概念,是记录ActivityRecord的栈,一个“Task”包含若干个ActivityRecord。AMS用TaskRecord确保Activity启动和退出的顺序。如果你清楚Activity的4种launchMode,那么对这个概念应该不陌生。
如果你还感到迷惑的话,就把这篇文章多读几遍吧,信息量可能比较多,需要慢慢消化~
尊重原创,转载请注明:From 凯子哥( 侵权必究!
关注我的微博,可以获得更多精彩内容
&a href=&/u/?s=6uyXnP& target=&_blank&&&img border=&0& src=&http://service..cn/widget/qmd//a.png&/&&/a&
文/裸奔的凯子哥(简书作者)
原文链接:/p/6037f6fda285
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
wenyiqingnianiii
排名:千里之外
(135)(52)(4)(11)(7)(6)(3)(2)(5)(1)(9)(4)}

我要回帖

更多关于 docker attach 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信