本文基于Android8.0源码。

启动流程图

点击可以看大图

ActivityManagerServiceActivityManagerServiceProcessProcessZygoteProcessZygoteProcessZygoteStateZygoteStateLocalSocketActivityThreadActivityThreadApplicationThreadZygoteInitZygoteInitZygoteServerZygoteConnectionZygoteZygoteRuntimeInitRuntimeInitmainZygoteServerregisterServerSocketnew LocalServerSocket()runSelectLoopwhile(true)Os.poll()startProcessLockedstartstartstartViaZygote组装zygote参数openZygoteSocketIfNeededconnectLocalSocketnew LocalSocketAddressconnectconnectacceptCommandPeercreateNewConnectionZygoteConnectionZygoteStatezygoteSendArgsAndGetResult(BufferedWriter)write(arg)read socketrunOnceforkAndSpecializepidif (pid>0) handleParentProcwrite pidread pidreturn ProcessStartResultreturn ProcessStartResultif (pid==0) handleChildProczygoteInitnativeZygoteInitapplicationInitinvokeStaticMainthrows Zygote.MethodAndArgsCallermain() catch ExceptionmainLooper.prepareMainLooper()new ActivityThread()ApplicationThreadattach(IApplicationThread)attachApplicationBinder.getCallingPid()attachApplicationLockedfind ProcessRecord by pidbindApplicationLooper.loop()
阅读全文 »

工具

在线编译工具:http://viz-js.com
VSCode安装插件:Graphviz (dot) language support for Visual Studio Code
命令行:dot,比如,dot -Tpng -ofile.png file.dot可以导出图片。在Ubuntu系统中,通过sudo apt install graphviz安装即可使用。

添加系统环境变量:

GRAPHVIZ_DOT = D:\Program Files\Graphviz\bin\dot.exe

学习资料

Node Shapes
Graphviz (dot) examples
Node, Edge and Graph Attributes

常用属性介绍

节点(node)属性

节点的形状主要有三种:Polygon-based Nodes, Record-based Nodes, User-defined Nodes。点击链接可看到详细介绍。

属性名称 介绍
shape 节点形状,box长方形、circle圆形等,参考Node Shapes
color 边框颜色
style 节点样式,filled, invisible, diagonals等,参考Styles for Nodes
fillcolor 填充颜色, 只有在style=filled时才生效
fontcolor 文字颜色
阅读全文 »

VSCode + Hexo

安装Paste Image插件

安装完插件后,通过 Ctrl + Shift + P 快捷键打开setting.json
Open Settings(JSON)

然后,在setting.json文件中添加两行配置

1
2
"pasteImage.path": "${currentFileNameWithoutExt}/",
"pasteImage.insertPattern": "{% asset_img ${imageFileName} %}",

然后就可以使用Ctrl + Alt + V快捷键就可以粘贴图片到markdown文档中了。但是这个快捷键不一定好使。也可以通过Ctrl + Shift + P然后输入past image来粘贴。
插入的图片采用asset_img语法,关于asset_img详细信息可参考:https://hexo.io/docs/asset-folders。插入的图片将会放到markdown文件同名的文件夹中。

安装Markdown Preview Enhanced插件

Markdown Preview Enhanced插件无法展示使用asset_img插入的图片,需要修改插件的parser.js。通过快捷键Ctrl+Shift+P打开parser.js:
Extent Parser
然后修改onWillParseMarkdown函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
onWillParseMarkdown: function(markdown) {
var vscode = require("vscode");
var path = require("path");
return new Promise((resolve, reject)=> {
markdown = markdown.replace(
/\{%\s*asset_img\s*(\S+)\s*\S*\s*%\}/g,
(whole, content) => {
abs_filename = vscode.window.activeTextEditor.document.fileName
filename = path.basename(abs_filename);
filename = filename.substring(0,filename.indexOf('.'))
return `![](${filename + "/"+ content})`;
}
)
return resolve(markdown)
})
},

参考文章:

阅读全文 »

本文基于Android8.0源码

Android8.0使用的java虚拟机为ART,在大名鼎鼎的zygote进程中启动java虚拟机。
首先看一下zygote的main函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//app_main.cpp
int main(int argc, char* const argv[])
{
//AppRuntime继承自AndroidRuntime, 构造函数中没有什么有用信息,可以不关注
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
//...
if (zygote) {
//调用到AndroidRuntime.start函数启动zygote进程的虚拟机
//传入的第一个参数是java类ZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}

runtime.start会调用父类的AndroidRuntime::start,看一下实现

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
//AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
......
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL); // 1. 加载虚拟机动态库,并加载库函数符号
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { // 2. 启动虚拟机
return;
}
onVmCreated(env);

/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
......

if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//调用com.android.internal.os.ZygoteInit的main函数,从此便进入了Java的世界
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
}
  1. 加载虚拟机动态库,并加载库函数符号
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
//JniInvocation.cpp

bool JniInvocation::Init(const char* library) {
......
library = GetLibrary(library, buffer); //返回“libart.so” art虚拟机库
......
handle_ = dlopen(library, kDlopenFlags); //动态加载虚拟机so库
......
//下面的三个if语句都是通过dlsym来获取虚拟机so库中的函数符号
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
"JNI_GetDefaultJavaVMInitArgs")) {
return false;
}
//无比重要的函数,获取虚拟机构造函数的函数符号,创建虚拟机全靠JNI_CreateJavaVM
if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
"JNI_CreateJavaVM")) {
return false;
}
if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
"JNI_GetCreatedJavaVMs")) {
return false;
}
return true;
}
jint JniInvocation::JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JNI_CreateJavaVM_(p_vm, p_env, vm_args);
}

//该函数就是最终创建虚拟机的函数
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}
  1. 启动虚拟机
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* Start the Dalvik Virtual Machine.
*/
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
...... //组装虚拟机启动参数
/*
* Initialize the VM.
*
* The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
* If this call succeeds, the VM is ready, and we can start issuing
* JNI calls.
*/
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}

return 0;
}
阅读全文 »

SOLID


Single responsibility principle 单一职责

The single responsibility principle is a computer programming principle that states that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class, module or function. All its services should be narrowly aligned with that responsibility. Robert C. Martin expresses the principle as, “A class should have only one reason to change,” although, because of confusion around the word “reason” he more recently stated “This principle is about people.(Actor)”

Martin defines a responsibility as a reason to change, and concludes that a class or module should have one, and only one, reason to be changed (i.e. rewritten). As an example, consider a module that compiles and prints a report. Imagine such a module can be changed for two reasons. First, the content of the report could change. Second, the format of the report could change. These two things change for very different causes; one substantive, and one cosmetic. The single responsibility principle says that these two aspects of the problem are really two separate responsibilities, and should therefore be in separate classes or modules. It would be a bad design to couple two things that change for different reasons at different times.

The reason it is important to keep a class focused on a single concern is that it makes the class more robust. Continuing with the foregoing example, if there is a change to the report compilation process, there is greater danger that the printing code will break if it is part of the same class.

Open–closed principle 开闭原则

Open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behaviour to be extended without modifying its source code.

The name open/closed principle has been used in two ways. Both ways use generalizations (for instance, inheritance or delegate functions) to resolve the apparent dilemma, but the goals, techniques, and results are different.

Liskov substitution principle 里式替换

阅读全文 »

使用的工具

dex转换为jar

1
d2j-dex2jar.sh -f ~/path/to/apk_to_decompile.apk

生成jar包后,需要使用JD-GUI打开查看

在macos上打开JD-GUI可能会报下面错误:

1
2
3
No suitable Java version found on your system!
This program requires Java 1.8+
Make sure you install the required Java version.

解决方案:在JD-GUI应用程序右击,然后选择“显示包内容”,然后打开Contents/MacOS/universalJavaApplicationStub.sh文件,找到这个报错的打印位置,把JAVA_HOME赋值为jdk home路径即可。

反编译为Smali

1
java -jar apktool_2.8.1.jar decode -o apk_smali app.apk
阅读全文 »
0%