Zygote进程启动流程(转)

Zygote进程启动流程(转)

大家都知道android系统的Zygote进程是所有的android进程的父进程,包括SystemServer和各种应用进程都是通过Zygote进程fork出来的。Zygote(孵化)进程相当于是android系统的根进程,后面所有的进程都是通过这个进程fork出来的,而Zygote进程则是通过linux系统的init进程启动的,也就是说,android系统中各种进程的启动方式

init进程 –> Zygote进程 –> SystemServer进程 –>各种应用进程

  • init进程:linux的根进程,android系统是基于linux系统的,因此可以算作是整个android操作系统的第一个进程;

  • Zygote进程:android系统的根进程,主要作用:可以作用Zygote进程fork出SystemServer进程和各种应用进程;

  • SystemService进程:主要是在这个进程中启动系统的各项服务,比如ActivityManagerService,PackageManagerService,WindowManagerService服务等等;

  • 各种应用进程:启动自己编写的客户端应用时,一般都是重新启动一个应用进程,有自己的虚拟机与运行环境;

本文主要介绍一下Zygote进程的启动流程,关于SystenServer进程和各种应用进程的启动方式会在以后的文章中介绍。

init进程在启动Zygote进程时一般都会调用ZygoteInit类的main方法,因此我们这里看一下该方法的具体实现(基于android23源码);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public static void main(String argv[]) {
try {
RuntimeInit.enableDdms();
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();

boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; 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());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}

if (abiList == null) {
throw new RuntimeException("No ABI list supplied.");
}

registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());

// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();

// Do an initial gc to clean up after startup
gcAndFinalize();

// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);

if (startSystemServer) {
startSystemServer(abiList, socketName);
}

Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);

closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
android之LruCache(转)

android之LruCache(转)

android开发过程中经常会用到缓存,现在主流的app中图片等资源的缓存策略一般是分两级,一个是内存级别的缓存,一个是磁盘级别的缓存。

作为android系统的维护者google也开源了其缓存方案,LruCache和DiskLruCache。从android3.1开始LruCache已经作为android源码的一部分维护在android系统中,为了兼容以前的版本android的support-v4包也提供了LruCache的维护,如果App需要兼容到android3.1之前的版本就需要使用support-v4包中的LruCache,如果不需要兼容到android3.1则直接使用android源码中的LruCache即可,这里需要注意的是DiskLruCache并不是android源码的一部分。

在LruCache的源码中,关于LruCache有这样的一段介绍:

1
A cache that holds strong references to a limited number of values. Each time a value is accessed, it is moved to the head of a queue. When a value is added to a full cache, the value at the end of that queue is evicted and may become eligible for garbage collection.

cache对象通过一个强引用来访问内容。每次当一个item被访问到的时候,这个item就会被移动到一个队列的队首。当一个item被添加到已经满了的队列时,这个队列的队尾的item就会被移除。

其实这个实现的过程就是LruCache的缓存策略,即Lru–>(Least recent used)最少最近使用算法。

下面我们具体看一下LruCache的实现:

android之Log日志(转)

android之Log日志(转)

首先说点题外话,对于想学android framework源码的同学,其实可以在github中fork一份,具体地址:platform_frameworks_base
这里面基本都是android framework层的源码了。而且最近发现了一个比较不错的github插件:OctoTree,它 是一个浏览器插件,它可以让你在Github 看代码时,左边栏会出现一个树状结构,就像我们在IDE 一样。当我们看一个项目的结构,或者想看具体的某个文件,这样就会很方便。
image

怎么样这样查看源代码的话是不是很方面?

好了说一下我们今天需要介绍的Log对象,它位于android framework层utils包下,是一个final class类:查看其具体定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
public final class Log {

/**
* Priority constant for the println method; use Log.v.
*/
public static final int VERBOSE = 2;

/**
* Priority constant for the println method; use Log.d.
*/
public static final int DEBUG = 3;

/**
* Priority constant for the println method; use Log.i.
*/
public static final int INFO = 4;

/**
* Priority constant for the println method; use Log.w.
*/
public static final int WARN = 5;

/**
* Priority constant for the println method; use Log.e.
*/
public static final int ERROR = 6;

/**
* Priority constant for the println method.
*/
public static final int ASSERT = 7;

private Log() {
}

/**
* Send a {@link #VERBOSE} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int v(String tag, String msg) {
return println(LOG_ID_MAIN, VERBOSE, tag, msg);
}

/**
* Send a {@link #VERBOSE} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int v(String tag, String msg, Throwable tr) {
return println(LOG_ID_MAIN, VERBOSE, tag, msg + '\n' + getStackTraceString(tr));
}

/**
* Send a {@link #DEBUG} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int d(String tag, String msg) {
return println(LOG_ID_MAIN, DEBUG, tag, msg);
}

/**
* Send a {@link #DEBUG} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int d(String tag, String msg, Throwable tr) {
return println(LOG_ID_MAIN, DEBUG, tag, msg + '\n' + getStackTraceString(tr));
}

/**
* Send an {@link #INFO} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int i(String tag, String msg) {
return println(LOG_ID_MAIN, INFO, tag, msg);
}

/**
* Send a {@link #INFO} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int i(String tag, String msg, Throwable tr) {
return println(LOG_ID_MAIN, INFO, tag, msg + '\n' + getStackTraceString(tr));
}

/**
* Send a {@link #WARN} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int w(String tag, String msg) {
return println(LOG_ID_MAIN, WARN, tag, msg);
}

/**
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int w(String tag, String msg, Throwable tr) {
return println(LOG_ID_MAIN, WARN, tag, msg + '\n' + getStackTraceString(tr));
}

/*
* Send a {@link #WARN} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param tr An exception to log
*/
public static int w(String tag, Throwable tr) {
return println(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr));
}

/**
* Send an {@link #ERROR} log message.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
*/
public static int e(String tag, String msg) {
return println(LOG_ID_MAIN, ERROR, tag, msg);
}

/**
* Send a {@link #ERROR} log message and log the exception.
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @param tr An exception to log
*/
public static int e(String tag, String msg, Throwable tr) {
return println(LOG_ID_MAIN, ERROR, tag, msg + '\n' + getStackTraceString(tr));
}

/**
* Handy function to get a loggable stack trace from a Throwable
* @param tr An exception to log
*/
public static String getStackTraceString(Throwable tr) {
if (tr == null) {
return "";
}

// This is to reduce the amount of log spew that apps do in the non-error
// condition of the network being unavailable.
Throwable t = tr;
while (t != null) {
if (t instanceof UnknownHostException) {
return "";
}
t = t.getCause();
}

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
tr.printStackTrace(pw);
pw.flush();
return sw.toString();
}

/**
* Low-level logging call.
* @param priority The priority/type of this log message
* @param tag Used to identify the source of a log message. It usually identifies
* the class or activity where the log call occurs.
* @param msg The message you would like logged.
* @return The number of bytes written.
*/
public static int println(int priority, String tag, String msg) {
return println(LOG_ID_MAIN, priority, tag, msg);
}

/** @hide */ public static final int LOG_ID_MAIN = 0;
/** @hide */ public static final int LOG_ID_RADIO = 1;
/** @hide */ public static final int LOG_ID_EVENTS = 2;
/** @hide */ public static final int LOG_ID_SYSTEM = 3;
/** @hide */ public static final int LOG_ID_CRASH = 4;

/** @hide */ @SuppressWarnings("unused")
public static int println(int bufID,
int priority, String tag, String msg) {
return 0;
}
}

可以看到其实final 类,所以我们不能通过继承Log类的方式实现自身的日志工具类,一般的我们可以通过定义Log成员变量的方式,封装Log工具方法;

android之IntentService(转)

android之IntentService(转)

什么是IntentService?简单来说IntentService就是一个含有自身消息循环的Service,首先它是一个service,所以service相关具有的特性他都有,同时他还有一些自身的属性,其内部封装了一个消息队列和一个HandlerThread,在其具体的抽象方法:onHandleIntent方法是运行在其消息队列线程中,废话不多说,我们来看其简单的使用方法:

  • 定义一个IntentService
1
2
3
4
5
6
7
8
9
10
11
12
public class MIntentService extends IntentService{

public MIntentService() {
super("");
}

@Override
protected void onHandleIntent(Intent intent) {
Log.i("tag", intent.getStringExtra("params") + " " + Thread.currentThread().getId());
}

}
  • 在androidManifest.xml中定义service
1
2
3
<service
android:name=".MIntentService"
/>
  • 启动这个service
1
2
3
4
5
6
7
8
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MIntentService.class);
intent.putExtra("params", "ceshi");
startService(intent);
}
});

可以发现当点击title组件的时候,service接收到了消息并打印出了传递过去的intent参数,同时显示onHandlerIntent方法执行的线程ID并非主线程,这是为什么呢?

android之HandlerThread(转)

android之HandlerThread(转)

HandlerThread是个什么东西?查看类的定义时有这样一段话:

1
Handy class for starting a new thread that has a looper. The looper can then be used to create handler classes. Note that start() must still be called.

意思就是说:这个类的作用是创建一个包含looper的线程。
那么我们在什么时候需要用到它呢?加入在应用程序当中为了实现同时完成多个任务,所以我们会在应用程序当中创建多个线程。为了让多个线程之间能够方便的通信,我们会使用Handler实现线程间的通信。这个时候我们手动实现的多线程+Handler的简化版就是我们HandlerThrea所要做的事了。

下面我们首先看一下HandlerThread的基本用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
HandlerThread mHandlerThread = new HandlerThread("myHandlerThreand");
mHandlerThread.start();

// 创建的Handler将会在mHandlerThread线程中执行
final Handler mHandler = new Handler(mHandlerThread.getLooper()) {
@Override
public void handleMessage(Message msg) {
Log.i("tag", "接收到消息:" + msg.obj.toString());
}
};

title = (TextView) findViewById(R.id.title);
title.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {

Message msg = new Message();
msg.obj = "11111";
mHandler.sendMessage(msg);

msg = new Message();
msg.obj = "2222";
mHandler.sendMessage(msg);
}
});
android异步任务AsyncTask(转)

android异步任务AsyncTask(转)

android的异步任务体系中还有一个非常重要的操作类:AsyncTask,其内部主要使用的是java的线程池和Handler来实现异步任务以及与UI线程的交互。本文主要解析AsyncTask的的使用与源码。

首先我们来看一下AsyncTask的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class MAsyncTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected void onPreExecute() {
super.onPreExecute();
Log.i(TAG, "onPreExecute...(开始执行后台任务之前)");
}

@Override
protected void onPostExecute(Integer i) {
super.onPostExecute(i);
Log.i("TAG", "onPostExecute...(开始执行后台任务之后)");
}

@Override
protected Integer doInBackground(Integer... params) {
Log.i(TAG, "doInBackground...(开始执行后台任务)");
return 0;
}
}

我们定义了自己的MAsyncTask并继承自AsyncTask;并重写了其中的是哪个回调方法:onPreExecute(),onPostExecute(),doInBackground();
然后开始调用异步任务:

1
new MAsyncTask().execute();

好了,下面我们开始分析异步任务的执行过程,首先查看一下异步任务的构造方法:

android异步消息机制(转)

android异步消息机制(转)

知乎上看了一篇非常不错的博文:有没有必要阅读ANDROID源码
痛定思过,为了更好的深入android体系,决定学习android framework层源码,就从最简单的android异步消息机制开始吧。

(一)Handler的常规使用方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MainActivity extends AppCompatActivity {

public static final String TAG = MainActivity.class.getSimpleName();
private TextView texttitle = null;

/**
* 在主线程中定义Handler,并实现对应的handleMessage方法
*/
public static Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 101) {
Log.i(TAG, "接收到handler消息...");
}
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

texttitle = (TextView) findViewById(R.id.texttitle);
texttitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new Thread() {
@Override
public void run() {
// 在子线程中发送异步消息
mHandler.sendEmptyMessage(101);
}
}.start();
}
});
}
}

可以看出,一般handler的使用方式都是在主线程中定义Handler,然后在子线程中调用mHandler.sendEmptyMessage();方法,然么这里有一个疑问了,我们可以在子线程中定义Handler么?

android项目构建流程(转)

android项目构建流程(转)

平时开发过程中我们通过android studio编写完成android项目之后直接点击 Run ‘app’就可以在build/outputs/apk生成可以在android设备中安装的apk文件了,那么整个android源码的构建过程是怎么样的呢?

我们可以根据Google官方提供的流程图来具体了解构建的过程:
image

通常的构建过程就是如上图所示,下面是具体描述:

1.AAPT(Android Asset Packaging Tool)工具会打包应用中的资源文件,如AndroidManifest.xml、layout布局中的xml等,并将xml文件编译为二进制形式,当然assets文件夹中的文件不会被编译,图片及raw文件夹中的资源也会保持原来的形态,需要注意的是raw文件夹中的资源也会生成资源id。AAPT编译完成之后会生成R.java文件。

2.AIDL工具会将所有的aidl接口转化为java接口。

3.所有的java代码,包括R.java与aidl文件都会被Java编译器编译成.class文件。

4.Dex工具会将上述产生的.class文件及第三库及其他.class文件编译成.dex文件(dex文件是Dalvik虚拟机可以执行的格式),dex文件最终会被打包进APK文件。

5.ApkBuilder工具会将编译过的资源及未编译过的资源(如图片等)以及.dex文件打包成APK文件。

6.生成APK文件后,需要对其签名才可安装到设备,平时测试时会使用debug keystore,当正式发布应用时必须使用release版的keystore对应用进行签名。

7.如果对APK正式签名,还需要使用zipalign工具对APK进行对齐操作,这样做的好处是当应用运行时会减少内存的开销。

热修复技术原理总结

热修复技术原理总结

#1.什么是热修复

传统更新流程:版本上线->用户安装->发现bug->紧急修复->重新发版->用户安装

弊端
:重新发版本代价高

:用户下载安装成本高

:bug修复不及时,体验差

解决方案
Hybrid方案:业务逻辑以H5方式加载
插件化方案:Atlas或者DroidPlugin方案
热修复方案:采用热修复技术,将更新补丁上传到云端,APP从云端下拉补丁直接应用生效
热修复更新流程:版本上线->用户安装->发现bug->紧急修复->打出补丁,推送给用户->自动拉取补丁修复
优势
1.无需重新发版,实时高效热修复
2.用户无感知修复,无需下载新应用,代价小
3.修复成功率高,把损失降到最低

Android 项目中so文件丢失

:D 一言句子获取中...