├── .gitignore
├── Framework
├── Activity启动流程.md
├── Activity的显示原理.md
├── Android启动机制汇总与对比.md
├── Android系统显示原理-SurfaceFlinger.md
├── Context.md
├── FutureTask.md
├── Handler.md
├── IPC通信的方式汇总.md
├── Provider跨进程通信.md
├── U-boot源码分析.md
├── UI线程的启动.md
├── Vsync原理.md
├── ashmem匿名共享内存.md
├── image
│ ├── Activity启动图1.png
│ ├── Activity的显示原理.png
│ ├── Binder分层结构.png
│ ├── Binder组成机制.png
│ ├── Binder请求协议.png
│ ├── Context继承关系.png
│ ├── Service启动过程.png
│ ├── SurfaceFlinger系统层显示原理.png
│ ├── Vsync事件分发流程.png
│ ├── Vsync信号分发原理.png
│ ├── Vsync信号流向.png
│ ├── Vsync原理.png
│ ├── 一般进程通信流程.png
│ ├── 多APP和SurfaceFlinger连接示意图.png
│ ├── 屏幕双缓冲示意图.png
│ └── 管道使用方式.png
├── zygote理解.md
├── 应用Service启动流程.md
├── 应用进程启动.md
├── 操作系统基础-通信机制-内存管理基础.md
├── 添加系统服务.md
└── 系统启动.md
├── README.md
├── 信息安全
├── 个人信息安全APP治理存在问题.md
├── 侵权占比.png
├── 信息安全生命周期.png
├── 内部制度建立.png
├── 处理方向.png
├── 数据汇聚融合.png
├── 未公开收集使用权限.png
├── 未按法律规定.png
├── 未明示收集个人信息目的.png
├── 未经同意使用.png
├── 未经同意提供三方.png
├── 现状1.png
├── 现状2.png
├── 现状3.png
└── 违反必要原则.png
├── 工程杂记
├── Visual VM使用说明.md
├── cmake基础语法.md
├── image
│ ├── 坐标转换.jpg
│ ├── 摆放位置影响1.png
│ └── 摆放位置影响2.png
├── markdown生成目录.md
├── 获取AOSP工程步骤.md
└── 计算机视觉在A3项目中应用.md
├── 应用优化
├── AOP框架Aspectjx使用.md
├── Surface采集与传输优化.md
├── image
│ ├── traceView查看阶段耗时.png
│ └── 问题帧展示结果.png
├── 内存优化.md
├── 单例模式.md
├── 卡顿优化.md
├── 启动优化.md
└── 绘制原理.md
├── 思想指导
├── image
│ ├── 28法则.jpeg
│ ├── PDCA内容.png
│ ├── smart原则.png
│ ├── 干重要的事情.png
│ ├── 时间管理title.jpg
│ ├── 时间管理四象限.png
│ ├── 计划示例.png
│ ├── 认识论.png
│ └── 马克思社会辩证法.png
├── 如何进行高效时间管理.md
├── 毛泽东选集
│ ├── 实践论.md
│ ├── 战争和战略问题.xmind
│ ├── 矛盾论.md
│ ├── 矛盾论.xmind
│ └── 社会辩证法.xmind
├── 金字塔原理.md
└── 马克思社会辩证法.md
├── 新兴语言
└── Kotlin.md
├── 网络基础
├── ARP_ICMP.md
├── Chromium浏览器内核分析
│ └── 线程调度.md
├── HTTP.md
├── HTTP头部.png
├── IP和路由收发流程.png
├── TCP.md
├── UDP.md
└── tcp进行网络通信的过程.png
├── 视频开发
├── MediaPlayer.md
├── ijkplayer集成和使用.md
└── 音视频基础知识.md
└── 语言基础
├── HashMap.md
├── JVM-Dalvik-Art.md
├── java并发.md
└── 编程珠玑.md
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.ini
3 | .SynologyWorkingDirectory/
4 |
--------------------------------------------------------------------------------
/Framework/Activity启动流程.md:
--------------------------------------------------------------------------------
1 | ## 问题
2 |
3 | 1. Activity 启动生命周期回调
4 | 2. 启动涉及到的组件和通信过程
5 | 3. 生命周期回调原理
6 |
7 |
8 |
9 | ### 启动原理
10 |
11 | 1. startActivity ---> 拿到AMS binder对象 ---> transact ---> AMS.onTransact()
12 |
13 | 2. AMS查询进程是否启动。 processRecord -->进程启动流程参考 [进程启动](./应用进程启动.md)
14 | 3. mFocusedStack --- > ActivityRecord -->
15 | 4. ProcessRecord.Thread.SheduleLaunchActivity 封装消息发送到主线程
16 | 5. 创建Activity 对象 --> 准备好 Application ---> 创建ContextImpl ---->
17 |
18 | attach Context ----> 生命周期回调。
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Framework/Activity的显示原理.md:
--------------------------------------------------------------------------------
1 | ## 相关问题
2 |
3 | Activity的显示原理 Window/DecorView/ViewRoot
4 |
5 | Activity 的UI刷新机制 Vsync / Choreography
6 |
7 | UI的绘制原理 Measure /Layout/ Draw
8 |
9 | Surface原理 Surface/ SurfaceFlinger
10 |
11 |
12 |
13 | ## 问题描述
14 |
15 | 1. setContentView原理是什么
16 | 2. Activity在OnResume 才显示原因什么?
17 | 3. ViewRoot 是干什么的?
18 |
19 |
20 |
21 | ### 原理讲解:
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 1. setContentView()
30 |
31 | ```java
32 | //Activity.java
33 | public void setContentView(@LayoutRes int layoutResID) {
34 | //getWindow 返回 PhoneWindow
35 | getWindow().setContentView(layoutResID); --->
36 | ..
37 | }
38 | ```
39 |
40 |
41 |
42 | 2. attach 会调用创建PhoneWindow,用于管理手机窗口
43 |
44 | ```java
45 | //PhoneWindow.java
46 |
47 | public void setContentView(int layoutResID) {
48 | if (mContentParent == null) {
49 | //创建Decor View
50 | installDecor();
51 | }
52 | // 加载布局,并解析 生成ViewTree
53 | mLayoutInflater.inflate(layoutResID, mContentParent);
54 | }
55 | ```
56 |
57 |
58 |
59 | 3. OnResume之后展示出来
60 |
61 | ```java
62 | //ActivityThread
63 | public void handleResumeActivity(IBinder token, ..) {
64 | // TODO Push resumeArgs into the activity for consideration
65 | // 调用Activity的 Resume 生命周期方法
66 | final ActivityClientRecord r = performResumeActivity(token, ..);
67 | View decor = r.window.getDecorView();
68 | decor.setVisibility(View.INVISIBLE);
69 | // ***
70 | ViewRootImpl impl = decor.getViewRootImpl();
71 | ViewManager wm = a.getWindowManager(); ---->
72 | wm.addView(decor, l);
73 | // 进行一次重绘
74 | r.activity.makeVisible();
75 | }
76 | ```
77 |
78 | 4. windowManagerImpl.java
79 |
80 | ```java
81 | //WindowManagerImpl ---> WindowManagerGlobal.java
82 | public void addView(View view,..){
83 | ViewRootImpl root;
84 | root = new ViewRootImpl(view.getContext(), display);
85 | mViews.add(view);
86 | mRoots.add(root);
87 | root.setView(view, wparams, panelParentView); ---->
88 | }
89 |
90 | ```
91 |
92 | 5. ViewRootImpl.java
93 |
94 | ```java
95 | public void setView(View view, ..) {
96 | // Schedule the first layout -before- adding to the window
97 | // manager, to make sure we do the relayout before receiving
98 | // any other events from the system.
99 | // 触发第一次绘制
100 | requestLayout();
101 | //-->scheduleTraversals()
102 | // 加入到 Choreography /ˌkɒriˈɒɡrəfi/ Vsync 到来时候会触发 界面刷新
103 | //--> mChoreographer.postCallback(mTraversalRunnable)
104 | // 申请Surface
105 |
106 | mWindowSession.addToDisplay(mWindow, mSeq,...);
107 | //mWindow 是->IWindow.Stub
108 | // mWindowSession 是 WMS 创建的通信句柄
109 | // WMS.addWindow( ) 建立双向通信机制
110 | }
111 |
112 | ```
113 |
114 | WMS作用:
115 |
116 | 1. 分配 Surface
117 | 2. 掌管Surface显示顺序及其位置尺寸等
118 | 3. 控制窗口动画
119 | 4. 输入事件分发
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | ### 相关知识点
132 |
133 | 为什么OnMeasure 会被多次调用?
134 |
135 |
136 |
137 | //ViewRootImpl.java
138 |
139 | ```java
140 | void scheduleTraversals() {
141 | if (!mTraversalScheduled) {
142 | //postSyncBarrier 设置消息屏障,后面的消息暂时不处理,仅处理异步消息
143 |
144 | mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
145 | mChoreographer.postCallback(
146 | Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
147 | // doTraversal()
148 | notifyRendererOfFramePending();
149 | pokeDrawLockIfNeeded();
150 | }
151 | }
152 | // ||
153 | // \/
154 | private void performTraversals() {
155 | // Ask host how big it wants to be
156 | performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
157 |
158 | // Implementation of weights from WindowManager.LayoutParams
159 | // We just grow the dimensions as needed and re-measure if
160 | // needs be
161 | int width = host.getMeasuredWidth();
162 | int height = host.getMeasuredHeight();
163 | boolean measureAgain = false;
164 | // 这里说明 子View区域超过了父View 会进行重新测量
165 | if (lp.horizontalWeight > 0.0f) {
166 | width += (int) ((mWidth - width) * lp.horizontalWeight);
167 | childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
168 | MeasureSpec.EXACTLY);
169 | measureAgain = true;
170 | }
171 | if (lp.verticalWeight > 0.0f) {
172 | height += (int) ((mHeight - height) * lp.verticalWeight);
173 | childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
174 | MeasureSpec.EXACTLY);
175 | measureAgain = true;
176 | }
177 |
178 | if (measureAgain) {
179 | if (DEBUG_LAYOUT) Log.v(mTag,
180 | "And hey let's measure once more: width=" + width
181 | + " height=" + height);
182 | performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
183 | }
184 | }
185 | ```
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
--------------------------------------------------------------------------------
/Framework/Android启动机制汇总与对比.md:
--------------------------------------------------------------------------------
1 | # 一、Android 启动的服务
2 |
3 | 1. 干了什么事情?
4 | 2. 有哪些主要服务?
5 | 3. 都是干什么的?
6 |
7 |
8 |
9 | ## 1. Zygote
10 |
11 | 1. Zygote有什么作用? 孵化应用进程、启动SystemServer
12 | 2. 启动过程是怎么样的 ?
13 |
14 | C++ --> Java
15 |
16 | 创建虚拟机-- 初始化JNI---跳转JAVA
17 |
18 | --> 加载初始化资源---> 启动SystemServer --> 进入Loop循环 socket 等待消息处理
19 |
20 |
21 |
22 | 3. Zygote 是怎么孵化进程的?
23 | 4. Zygote 是怎么启动SystemServer的
24 |
25 | ZygoteInit --> forkSystemServer()
26 |
27 | -> Zygote.forkSystemServer()
28 |
29 | -->com_android_internal_os_Zygote_nativeForkSystemServer() ---> fork()
30 |
31 |
32 |
33 | linux 进程启动方式:
34 |
35 | ```java
36 | if(pid == fork() < 0){
37 | //error
38 | } else if (pid == 0) {
39 | //child Process
40 | execve()
41 | //--> 调用则独立资源
42 | // 不调用则共享 父进程资源
43 | // Copy On Write 写时复制技术
44 | } else {
45 | // parent process
46 | }
47 | ```
48 |
49 |
50 |
51 |
52 |
53 | 和U-Boot的异同
54 |
55 | | 项目 | Zygote | U-Boot |
56 | | ---------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
57 | | 跨语言启动 | C++ --> JAVA | 汇编 --> C |
58 | | 第一阶段 | 1. 初始化JVM环境
2. 初始化JNI
3. 跳转JAVA入口 | 1. 初始化硬件和SDRAM
2. 将C程序拷贝到内存
3. 跳转到C入口 |
59 | | 第二阶段 | 1. 初始化资源,主题等
2. 启动关键服务
3. 进入Loop循环等待用户交互 | 1. 初始化Flash、开始终端打印、网卡
2. 跳转到初始化入口-->执行Init进程、initrc
3. 进入Loop循环 |
60 |
61 |
62 |
63 | 总结:
64 |
65 | 1. Android启动阶段 分为了多个语言 阶段 汇编 -> C / C++ -->JAVA
66 | 2. 跨语言启动过程都进行了下一个阶段的初始化工作,并跳转到第二阶段入口
67 | 3. 一个存活的服务都需要在启动服务后进入Loop循环,等待被通信操作
68 |
69 |
70 |
71 |
72 |
73 | ## 2. SystemServer
74 |
75 | 1. SystemServer 是怎么启动的?
76 | 2. 启动干了什么事情呢?
77 |
78 | Zygote.forkSystemServer()
79 |
80 | 创建Systemserver进程 ---> 处理启动细节 handleSystemServerProcess、
81 |
82 |
83 |
84 | //ZygoteInit.zygoteInit()
85 |
86 | 1. RuntimeInit.commonInit(); 常规初始化、 解析配置参数、类加载等
87 |
88 | // AndroidRuntime.cpp
89 |
90 | 2. ZygoteInit.nativeZygoteInit(); 初始化Binder
91 |
92 | // RuntimeInit.java
93 |
94 | 3. RuntimeInit.applicationInit(classloader) 跳转到SystemServer java入口main函数
95 |
96 | // SystemServer.java 服务启动
97 |
98 | 1. 准备MainLooper
99 | 2. 创建 SystemServerManager 用于管理 后续创建的服务 用到类加载机制和反射
100 | 3. 分阶段启动服务, 分别有 bootstrapServices、CoreServices、OtherServices PID < 1000
101 | 4. 进入 Loop 循环
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | ## 3. ServiceManager
110 |
111 | init.rc --> start ServiceManager
112 |
113 | 1. 打开/dev/binder文件:open(“/dev/binder”, O_RDWR);
114 | 2. 建立128K内存映射:mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
115 | 3. *通知Binder驱动将自身注册为ServiceManager:binder_become_context_manager(bs);
116 | 4. 进入循环等待请求的到来:binder_loop(bs, svcmgr_handler);
117 |
118 |
119 |
120 |
121 | 服务的发布:
122 |
123 | 发布到ServicesManager:
124 |
125 | ServiceManager.addService("package", m); -- >
126 |
127 | getIServiceManager().addService(name, service, allowIsolated, dumpPriority)
128 |
129 |
130 |
131 | ## 4. AMS启动
132 |
133 |
134 |
135 |
136 |
137 | SystemServer -- > startBootstrapServices()
138 |
139 | ```java
140 | public static ActivityManagerService startService(
141 | SystemServiceManager ssm, ActivityTaskManagerService atm) {
142 | sAtm = atm;
143 | return ssm.startService(ActivityManagerService.Lifecycle.class).getService();
144 | }
145 | ```
146 |
147 |
148 |
149 | 1. 初始化资源 , 包括了AMS 线程HandlerThread 添加异常处理机制 WatchDog
150 |
151 | 2. AMS - > start() ,进行组件管理的必要初始化
152 |
153 |
154 |
155 | 3. AMS->setSystemProcess() 发布到 ServiceManager
156 |
157 | ```java
158 | ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
159 | DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
160 | ```
161 |
162 |
163 |
164 | 4. 启动Launcher/ systemUI
165 | //AMS -> systemReady() -- >
166 |
167 | ComponentName cName = new ComponentName(mContext, SystemUserHomeActivity.class);
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 | # 二、 Android 通信和网络通信对比
178 |
179 |
180 |
181 | ## 1. 通信方式
182 |
183 |
184 |
185 | ### 路由器示意图
186 |
187 | ****
188 |
189 |
190 |
191 | 1. 访问外部服务器,经过路由网络,找到下一跳服务器地址
192 | 2. 多级路由中保存了可达地址路由表
193 | 3. 查询路由表后, 将数据报文转发出去
194 |
195 |
196 |
197 | ### ServiceManager
198 |
199 |
200 |
201 |
202 |
203 | 1. 服务端启动服务,向ServiceManager 发布注册消息,并保存
204 | 2. 客户端 获取ServiceManager, 默认地址是0
205 | 3. 在ServiceManager中获取已注册发布的服务
206 | 4. 获取Service代理对象,完成通信
207 |
208 |
209 |
210 | ## 2. 通信协议
211 |
212 | ### TCP 通信协议:
213 |
214 | 
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 | ### Binder通信协议:
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 | 总结:
231 |
232 | 使用可靠的通信传输协议,保证消息的准确可达。
233 |
234 |
235 |
236 | ## 3. 软件层次
237 |
238 | ### 网络传输模型
239 |
240 | 
241 |
242 |
243 |
244 | ### Binder通信传输过程
245 |
246 |
247 |
248 |
249 |
250 | # 三、Android 其他IPC通信机制
251 |
252 |
253 |
254 | ## 1. 管道
255 |
256 | 1. 半双工的通信方式,若想实现全双工,则需要一对描述符。pipe(fds)
257 | 2. 一般在父子进程使用
258 | 3. 数据量小的跨进程通信
259 |
260 | 两次拷贝
261 |
262 | 使用到管道的组件:
263 |
264 | Looper
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 | ## 2. Socket
273 |
274 | 1. 全双工,可读可写
275 | 2. 在两个无亲缘关系的两个进程之间
276 | 3. 传输数据流不能太大
277 |
278 | 两次拷贝
279 |
280 |
281 |
282 | 使用Socket的组件
283 |
284 | Zygote --> AMS 通信
285 |
286 | ##
287 |
288 |
289 |
290 | ## 3. 共享内存
291 |
292 | 1. 快 不需要多次拷贝
293 | 2. 进程之间无需亲缘关系
294 | 3. 数据流较大的传输
295 |
296 |
297 |
298 | 使用共享内存地方:
299 |
300 | MemoryFile -> SharedMemory
301 |
302 | 创建文件描述符 --> 申请内存空间 --> Map 拷贝
303 |
304 |
305 |
306 | 图片传输相关
307 |
308 |
309 |
310 |
311 |
312 | ## 4. 信号
313 |
314 | 1. 单向, 无确认机制
315 | 2. 只能发信号,不能传参数
316 | 3. 只需知道PID即可发信号,可群发信号。
317 | 4. Root权限,或UID相同可发信号
318 |
319 |
320 |
321 | 信号的使用:
322 |
323 | 杀进程:
324 |
325 | ```java
326 | public static final void killProcess(int pid) {
327 | sendSignal(pid, SIGNAL_KILL);
328 | }
329 | ```
330 |
331 | Zygote 关注子进程退出流程:
332 |
333 | ```c++
334 | static void SetSignalHandlers() {
335 | struct sigaction sig_chld = {};
336 | sig_chld.sa_handler = SigChldHandler;
337 |
338 | if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
339 | ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
340 | }
341 |
342 | struct sigaction sig_hup = {};
343 | sig_hup.sa_handler = SIG_IGN;
344 | if (sigaction(SIGHUP, &sig_hup, nullptr) < 0) {
345 | ALOGW("Error setting SIGHUP handler: %s", strerror(errno));
346 | }
347 | }
348 | ```
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
--------------------------------------------------------------------------------
/Framework/Android系统显示原理-SurfaceFlinger.md:
--------------------------------------------------------------------------------
1 | ## 1. 关于`(Project Buffer)`
2 |
3 | Android 4.1 版本进行的UI流畅性优化, 重构了Android显示系统。其中包括三个核心元素:
4 |
5 | 1. **VSync**: (Vertical Synchronization , 垂直同步机制) 是一种定时中断机制,包括软件和硬件两种生成方式。
6 |
7 | 2. **双缓冲机制**: 包括两个Framebuffer,分别是Front Buffer和Back Buffer, 前者用于渲染显示,Back 用于预绘制,而后两者交换。
8 |
9 | 引入第三个buffer ----> Triple Buffer , 利用空闲的CPU时间。
10 |
11 | 3. **Choreography** :调度单元,管理用户注册的回调并完成调度策略。
12 |
13 |
14 |
15 |
16 |
17 | ### 为什么引双缓冲机制?存在什么问题又是怎么改进的?
18 |
19 |
20 | 我们先看4张 2012 年google I/O大会图:
21 |
22 | **1. 没有VSync信号**
23 |
24 |
25 |
26 | **2. 有VSync信号正常情况**
27 |
28 |
29 |
30 | **3. 有VSync信号但GPU处理能力不足,16ms内未渲染完成**
31 |
32 |
33 |
34 |
35 | **4. 三缓冲机制对情况三的优化**
36 |
37 |
38 |
39 | 四幅图中涉及到了三次优化,其最终目的都是如何更**有效的利用CPU和GPU资源**。
40 |
41 | 1. **双缓冲机制**的引入解决了单缓冲Screen Tearing现象的产生,也就是前后两帧画面各显示一部分。但这依然存在一个问题画面也就是`1图`绘制节奏的问题,可能CPU现在在处理其他任务,没来得及处理渲染下一阵画面,Back buffer 没准备好就只能显示前一帧画面,就出现了掉帧现象。
42 | 2. 问题在于优先级和绘制节奏,所以引入了**VSync信号机制**。VSync信号到来的时候就会启动下一帧的绘制工作,同时给主线程发送一个syncbarrier消息屏障,设置绘制动作为异步消息,以提高绘制的绝对优先级。但是在GPU或CPU处理能力不足的情况下,两个VSync信号间隔时间内完成不了渲染,但是两个Buffer又都被占用着。
43 | 3. **三缓冲机制**的引入缓解了这个问题, 当Vsync到来,但是Front Buffer 还在显示,Back Buffer依然在准备渲染数据的时候,就会使用Triple Buffer渲染下一帧数据,这事CPU和GPU会同时处理两帧数据,有效提高了资源利用率,减缓了掉帧现象。可以到`3图`中A、B两帧数据掉帧,而`4图`中由于三缓冲机制的引入B帧的数据得以正常显示。
44 |
45 |
46 |
47 |
48 |
49 | ## 2. SurfaceFlinger 的启动
50 |
51 | ### SurfaceFlinger 做了什么?
52 |
53 | 
54 |
55 |
56 |
57 | SurfaceFlinger 接受缓冲区,对它们进行合成,然后发送到屏幕。WindowManager 为 SurfaceFlinger 提供缓冲区和窗口元数据,而 SurfaceFlinger 可使用这些信息将 Surface 合成到屏幕。 可以典型的生产者消费者模型。
58 |
59 |
60 |
61 | ### 1. init进程 ---> surfaceflinger.rc
62 |
63 | ```c++
64 | //framework/native/services/surfaceflinger/surfaceflinger.rc
65 | service surfaceflinger /system/bin/surfaceflinger
66 | ```
67 |
68 | ### 2. 启动入口函数 --->main
69 |
70 | ```c++
71 | // frameworks/native/services/surfaceflinger/main_surfaceflinger.cpp
72 | int main(int, char**) {
73 | //1. 设置最大Binder线程池数4,并启动线程池
74 | // binder threads to 4.
75 | ProcessState::self()->setThreadPoolMaxThreadCount(4);
76 | // start the thread pool
77 | sp ps(ProcessState::self());
78 | ps->startThreadPool();
79 | // 2. 创建surfaceflinger 对象并初始化,设置线程优先级为 PRIORITY_URGENT_DISPLAY(-4)
80 | // instantiate surfaceflinger
81 | sp flinger = surfaceflinger::createSurfaceFlinger();
82 | setpriority(PRIO_PROCESS, 0, PRIORITY_URGENT_DISPLAY);
83 | // initialize before clients can connect
84 | flinger->init(); -----> //
85 |
86 | // 3. 服务发布到 ServiceManager
87 | // publish surface flinger
88 | sp sm(defaultServiceManager());
89 | sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
90 | IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
91 |
92 | // 4. 执行启动入口
93 | // run surface flinger in this thread
94 | flinger->run(); ---->
95 |
96 | }
97 | ```
98 |
99 | ### 3. 强指针首次被引用的时候调用 --->//SurfaceFlinger::onFirstRef
100 |
101 | ```c++
102 | void SurfaceFlinger::onFirstRef()
103 | {
104 | mEventQueue->init(this); // ----> MessageQueue mEventQueue
105 | }
106 | //frameworks/native/services/surfaceflinger/Scheduler
107 | //初始化消息队列, MessageQueue中包括了消息队列和消息处理机制
108 | void MessageQueue::init(const sp& flinger) {
109 | mFlinger = flinger;
110 | mLooper = new Looper(true);
111 | mHandler = new Handler(*this);
112 | }
113 |
114 | ```
115 |
116 |
117 |
118 | ### 4.SurfaceFlinger初始化内容 // surfaceFlinger::init()
119 |
120 | ```c++
121 | void SurfaceFlinger::init() {
122 | //1. EventThread 的初始化
123 | mSfConnectionHandle = mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
124 | resyncCallback, [this](nsecs_t timestamp) {
125 | mInterceptor->saveVSyncEvent(timestamp);
126 | });
127 |
128 | // 2. 创建渲染引擎
129 | mCompositionEngine->setRenderEngine(renderengine::RenderEngine::create(static_cast(defaultCompositionPixelFormat),renderEngineFeature, maxFrameBufferAcquiredBuffers));
130 | // set initial conditions (e.g. unblank default device)
131 | //3. 初始化显示设备
132 | initializeDisplays();
133 | // 4. 初始化 HWComposer(Hardware Compose硬件合成) --> 联接了硬件层和SurfaceFlinger,是绘制的核心类。
134 | mCompositionEngine->setHwComposer(getFactory().createHWComposer(getBE().mHwcServiceName));
135 |
136 | }
137 | ```
138 |
139 |
140 |
141 | ### 5. SurfaceFlinger 启动,进入Loop循环 等待消息 //SurfaceFlinger::run
142 |
143 | ```c++
144 | void SurfaceFlinger::run() {
145 | do {
146 | waitForEvent(); // -->
147 | // mEventQueue->waitMessage();
148 | // ---> 进入epoll_wait() 等待消息
149 | // do {
150 | // IPCThreadState::self()->flushCommands();
151 | // int32_t ret = mLooper->pollOnce(-1);
152 | // }
153 |
154 | } while (true);
155 | }
156 |
157 |
158 | // 收到消息后 调用handleMessage --> SurfaceFlinger::onMessageReceived
159 | void MessageQueue::Handler::handleMessage(const Message& message) {
160 | switch (message.what) {
161 | case INVALIDATE:
162 | android_atomic_and(~eventMaskInvalidate, &mEventMask);
163 | mQueue.mFlinger->onMessageReceived(message.what);
164 | break;
165 | }
166 | }
167 |
168 | ```
169 |
170 |
171 |
172 | ## 3. VSync信号流向
173 |
174 | 
175 |
176 |
177 |
178 |
179 |
180 | 1. VSync信号由HWC2 产生,并发送到SurfaceFlinger的onVsyncReceived方法
181 | 2. 由EventThread线程对Vsync信号进行入队操作
182 | 3. HandlerThread 在收到待处理的消息后,调用mFlinger->onMessageReceived()
183 |
184 |
185 |
186 | ## 4. 应用端VSync 信号的订阅和分发
187 |
188 | 订阅关系示意图:
189 |
190 | 
191 |
192 |
193 |
194 |
195 |
196 | 1. 对于VSync信号感兴趣的APP ( Choreography 后面会分析 )会和SurfaceFlinger建立一个连接`createDisplayEventConnection()`
197 |
198 | 2. 交由 `mScheduler`进行处理,并在MessageQueue中EventThread对象创建绑定关系
199 |
200 | ```c++
201 | mEventThread = eventThread;
202 | mEvents = eventThread->createEventConnection(std::move(resyncCallback));
203 | mEvents->stealReceiveChannel(&mEventTube);
204 | mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,this);
205 | ```
206 |
207 | 3. 分发消息给对应应用进程 // gui::BitTube详细的实现
208 |
209 | ```c++
210 | int MessageQueue::cb_eventReceiver(int fd, int events, void* data) {
211 | MessageQueue* queue = reinterpret_cast(data);
212 | return queue->eventReceiver(fd, events);
213 | }
214 |
215 | int MessageQueue::eventReceiver(int /*fd*/, int /*events*/) {
216 | ssize_t n;
217 | DisplayEventReceiver::Event buffer[8];
218 | while ((n = DisplayEventReceiver::getEvents(&mEventTube, buffer, 8)) > 0) {
219 | for (int i = 0; i < n; i++) {
220 | if (buffer[i].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
221 | mHandler->dispatchInvalidate();
222 | break;
223 | }
224 | }
225 | }
226 | return 1;
227 | }
228 | ```
229 |
230 |
231 |
232 |
233 |
234 | ## 5. SurfaceFlinger 核心处理流程 ---->//handleMessageRefresh();
235 |
236 | 此时进入SurfaceFlinger的核心功能流程,在此先介绍下核心函数。
237 |
238 | ```c++
239 | void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
240 | ATRACE_CALL();
241 | switch (what) {
242 | case MessageQueue::INVALIDATE: {
243 | // ...
244 | //省略代码功能 1. 记录绘制状态和丢帧情况
245 |
246 | // 判断是否需要刷新
247 | bool refreshNeeded = handleMessageTransaction();
248 | refreshNeeded |= handleMessageInvalidate();
249 |
250 | updateCursorAsync();
251 | updateInputFlinger();
252 |
253 | refreshNeeded |= mRepaintEverything;
254 | if (refreshNeeded && CC_LIKELY(mBootStage != BootStage::BOOTLOADER)) {
255 | // Signal a refresh if a transaction modified the window state,
256 | // a new buffer was latched, or if HWC has requested a full
257 | // repaint
258 | // 这里执行刷新 -->
259 | signalRefresh();
260 | // ---->
261 | //void MessageQueue::refresh() {
262 | // mHandler->dispatchRefresh(); ---->
263 | //}
264 | // 最终 调用核心代码 handleMessageRefresh();
265 |
266 | }
267 | }
268 | case MessageQueue::REFRESH: {
269 |
270 | // ***核心代码***
271 | handleMessageRefresh();
272 |
273 | break;
274 | }
275 | }
276 | }
277 |
278 | ```
279 |
280 |
281 |
282 |
283 |
284 | ## handleMessageRefresh 绘制和叠加的核心流程内容
285 |
286 | ```c++
287 | void SurfaceFlinger::handleMessageRefresh() {
288 | ATRACE_CALL();
289 |
290 | mRefreshPending = false;
291 |
292 | const bool repaintEverything = mRepaintEverything.exchange(false);
293 |
294 | // 1. 合成前准备
295 | preComposition();
296 |
297 |
298 | // 2. 重新构建Layout 堆栈 ,按照Layout 的 z-order排序
299 | rebuildLayerStacks();
300 |
301 | calculateWorkingSet();
302 | for (const auto& [token, display] : mDisplays) {
303 | beginFrame(display);
304 | prepareFrame(display);
305 | doDebugFlashRegions(display, repaintEverything);
306 | // 3. 进行合成 可交给OpenGL ES 或 HWC模块
307 | // 最终是调用了 doComposeSurfaces 完成渲染
308 | // ---> doComposeSurfaces();
309 | // renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,buf->getNativeBuffer(), true, std::move(fd),readyFence);
310 | doComposition(display, repaintEverything);
311 | }
312 |
313 | logLayerStats();
314 |
315 | postFrame();
316 | //
317 | // ---> getRenderEngine().genTextures(refillCount, mTexturePool.data() + offset);
318 | // 4. 在物理屏幕渲染显示
319 | postComposition();
320 |
321 | mHadClientComposition = false;
322 | mHadDeviceComposition = false;
323 | for (const auto& [token, displayDevice] : mDisplays) {
324 | auto display = displayDevice->getCompositionDisplay();
325 | const auto displayId = display->getId();
326 | mHadClientComposition =
327 | mHadClientComposition || getHwComposer().hasClientComposition(displayId);
328 | mHadDeviceComposition =
329 | mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
330 | }
331 |
332 | mVsyncModulator.onRefreshed(mHadClientComposition);
333 |
334 | mLayersWithQueuedFrames.clear();
335 | }
336 | ```
337 |
338 |
339 |
340 | 多处看到有renderEngine的出现,实际上调用了 `gl::GLESRenderEngine ---> GLESRenderEngine.h` 。
341 |
342 |
343 |
344 |
345 |
346 |
347 |
--------------------------------------------------------------------------------
/Framework/Context.md:
--------------------------------------------------------------------------------
1 | ### 问题描述
2 |
3 | Context 是什么的?
4 |
5 | 有哪些组件有Context?
6 |
7 | 这些组件和Context什么关系?
8 |
9 | 不同的Context有什么区别?
10 |
11 |
12 |
13 | 先看一张类图:
14 |
15 |
16 |
17 | 
18 |
19 |
20 |
21 | #### 1. Context是什么?
22 |
23 | 看源码中的注释讲的非常清楚,不需要过多解释。简单说就是访问Android系统资源的媒介。
24 |
25 | ```java
26 | /**
27 | * Interface to global information about an application environment. This is
28 | * an abstract class whose implementation is provided by
29 | * the Android system. It allows access to application-specific resources and classes, as well as
30 | * up-calls for application-level operations such as launching activities,
31 | * broadcasting and receiving intents, etc.
32 | */
33 | ```
34 |
35 |
36 |
37 |
38 |
39 | #### 2. 几个关键函数说明Context的设置流程
40 |
41 | ```java
42 | @Override
43 | public Activity handleLaunchActivity(ActivityClientRecord r,
44 | PendingTransactionActions pendingActions, Intent customIntent) {
45 | // ...
46 | performLaunchActivity(r, customIntent);
47 | }
48 |
49 | // ActivityThread.java
50 | private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
51 | // 创建Base Context对象
52 | ContextImpl appContext = createBaseContextForActivity(r); // --> ContextImpl.createActivityContext
53 | // 获取classLoader 创建Activity对象
54 | java.lang.ClassLoader cl = appContext.getClassLoader();
55 | activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
56 | // 创建Application
57 | Application app = r.packageInfo.makeApplication(false, mInstrumentation);
58 | // 调用Attach,
59 | activity.attach(appContext, this, getInstrumentation(), r.token,
60 | r.ident, app, r.intent, r.activityInfo, title, r.parent,
61 | r.embeddedID, r.lastNonConfigurationInstances, config,
62 | r.referrer, r.voiceInteractor, window, r.configCallback,
63 | r.assistToken);
64 |
65 | }
66 |
67 |
68 | //1. Application Context 设置流程
69 | public Application makeApplication(boolean forceDefaultAppClass,
70 | Instrumentation instrumentation) {
71 | ava.lang.ClassLoader cl = getClassLoader();
72 | //
73 | app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);
74 |
75 |
76 | ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
77 | }
78 |
79 |
80 | //1. Application Context 设置流程
81 | public Application newApplication(ClassLoader cl, String className, Context context)
82 | throws InstantiationException, IllegalAccessException,
83 | ClassNotFoundException {
84 | Application app = getFactory(context.getPackageName())
85 | .instantiateApplication(cl, className);
86 | app.attach(context);
87 | return app;
88 | }
89 |
90 | //2. Activity 的Context 设置流程
91 | //Activity.java
92 | final void attach(Context context, ActivityThread aThread,...)
93 | {
94 | // 设置Base Context对象
95 | attachBaseContext(context);
96 |
97 | ...
98 | mWindow = new PhoneWindow(this, window, activityConfigCallback);
99 | ...
100 | }
101 |
102 |
103 | // ContextWrapper.java --> extends Context
104 | protected void attachBaseContext(Context base) {
105 | if (mBase != null) {
106 | throw new IllegalStateException("Base context already set");
107 | }
108 | mBase = base;
109 | }
110 | ```
111 |
112 |
113 |
114 |
--------------------------------------------------------------------------------
/Framework/FutureTask.md:
--------------------------------------------------------------------------------
1 | ### FutureTask是什么?
2 | FutureTask是一个可取消的异步计算。FutureTask实现了RunnableFuture接口,间接实现了Future和Runnable接口。在Future的基本实现中,提供了开始和取消一个计算的方法,同时可以查询计算是否完成并获取到计算结果。 仅当完成计算之后才能获取到计算结果,否则get方法将阻塞,直到计算完成。 计算完成之后这个计算将不能够重启或者取消,除非调用RunAndReset方法。
3 | Runnable的实现,赋予了FutureTask包裹Runnable或Callable的能力,因此FutureTask可以被提交到Executor中执行。
4 |
5 | ```java
6 | interface RunnableFuture extends Runnable, Future{}
7 | class FutureTask implements RunnableFuture{}
8 | ```
9 |
10 | #### FutureTask的状态转换
11 | FutureTask任务的运行状态,最初为NEW。运行状态仅在set、setException和cancel方法中转换为终端状态。在完成过程中,状态可能呈现出瞬时值INTERRUPTING(仅在中断运行程序以满足cancel(true)的情况下)或者COMPLETING(在设置结果时)状态时。从这些中间状态到最终状态使用 cheaper ordered/lazy writes(无锁同步CAS)策略, 原因是这些状态值是固定不可修改的。
12 |
13 | * NEW -> COMPLETING -> NORMAL
14 | * NEW -> COMPLETING -> EXCEPTIONAL
15 | * NEW -> CANCELLED
16 | * NEW -> INTERRUPTING -> INTERRUPTED
17 |
18 | ### FutureTask实现
19 | 这个类在实现上jdk 1.8 版本前后版本实现方式有些不同,之前使用的策略是AbstractQueuedsynchronizer也就是和ReentrantLock、ThreadPoolExecutor中的worker策略相同。 1.8版本是使用Usafe包中的Compare-And-Swap(CAS)特性实现。
20 |
21 | >Usafe包?
22 | >sun.misc.Unsafe 是sun公司的一个未开源的组件包,提供了些可以绕开JVM的一些方法,其中就包含了同步相关的一些方法。比如monitorEnter(),tryMonitorEnter(),monitorExit(),compareAndSwapInt(),putOrderedInt()。
23 | >
24 | >什么是CAS?
25 | >CAS是CPU提供的 用于解决多线程并行情况下使用锁造成性能损耗 的机制。
26 | >
27 | >如此优秀的特性,是不是尽情用就好了,当然不会尽善尽美,首先在Unsafe包中所有操作绕开了JVM意味着不会有人替你管理内存。 而且CAS会引入ABA问题。 更多内容请参考资料[[1]](http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/)
28 |
29 | 毋庸置疑根据前面描述的特性,FutureTask至少有一个cancel(), V get() 的public方法。
30 |
31 | ```java
32 | public boolean cancel(boolean mayInterruptIfRunning) {
33 | if (!(state == NEW &&
34 | U.compareAndSwapInt(this, STATE, NEW,
35 | mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
36 | return false;
37 | try { // in case call to interrupt throws exception
38 | if (mayInterruptIfRunning) {
39 | try {
40 | Thread t = runner;
41 | if (t != null)
42 | t.interrupt();
43 | } finally { // final state
44 | U.putOrderedInt(this, STATE, INTERRUPTED);
45 | }
46 | }
47 | } finally {
48 | finishCompletion();
49 | }
50 | return true;
51 | }
52 |
53 | /**
54 | * @throws CancellationException {@inheritDoc}
55 | */
56 | public V get() throws InterruptedException, ExecutionException {
57 | int s = state;
58 | if (s <= COMPLETING)
59 | s = awaitDone(false, 0L);
60 | return report(s);
61 | }
62 |
63 |
64 | ```
65 | cance()方法很好理解,就做量两件事1. 还能不能取消了,要不要终止线程取消。 2. 设置对应的状态。
66 | get()方法是去获取执行结果,但是现在如果没执行完呢? 前面说如果没执行完会阻塞等待,显然这是` s = awaitDone(false, 0L);`干的事情。
67 |
68 | 好像也不复杂。 对喽,稍微复杂的点地方在怎么去处理这个等待,怎么正确的同步处理状态。
69 |
70 | ```java
71 | /**
72 | * Awaits completion or aborts on interrupt or timeout.
73 | *
74 | * @param timed true if use timed waits
75 | * @param nanos time to wait, if timed
76 | * @return state upon completion or at timeout
77 | */
78 | private int awaitDone(boolean timed, long nanos)
79 | throws InterruptedException {
80 | // 下面的代码巧妙的实现了一下目标:
81 | // 每次请求到来的时候获取下精确的纳秒时间 nanoTime. (纳秒随机开始可能获取到负数)
82 | // 因此针对不同的值不同处理。
83 | // 被意外唤醒那么等一会。
84 | // The code below is very delicate, to achieve these goals:
85 | // - call nanoTime exactly once for each call to park
86 | // - if nanos <= 0L, return promptly without allocation or nanoTime
87 | // - if nanos == Long.MIN_VALUE, don't underflow
88 | // - if nanos == Long.MAX_VALUE, and nanoTime is non-monotonic
89 | // and we suffer a spurious wakeup, we will do no worse than
90 | // to park-spin for a while
91 | long startTime = 0L; // Special value 0L means not yet parked
92 | WaitNode q = null;
93 | boolean queued = false;
94 | for (;;) {
95 | int s = state;
96 | if (s > COMPLETING) {
97 | if (q != null)
98 | q.thread = null;
99 | return s;
100 | }
101 | else if (s == COMPLETING)
102 | // We may have already promised (via isDone) that we are done
103 | // so never return empty-handed or throw InterruptedException
104 | Thread.yield();
105 | else if (Thread.interrupted()) {
106 | removeWaiter(q);
107 | throw new InterruptedException();
108 | }
109 | else if (q == null) {
110 | if (timed && nanos <= 0L)
111 | return s;
112 | q = new WaitNode(); //用户方传入等待和时间两个参数 且时间>0 创建等待节点
113 | }
114 | else if (!queued)
115 | queued = U.compareAndSwapObject(this, WAITERS,
116 | q.next = waiters, q);
117 | else if (timed) { // 等待 传入参数nanos
118 | final long parkNanos;
119 | if (startTime == 0L) { // first time
120 | startTime = System.nanoTime();
121 | if (startTime == 0L)
122 | startTime = 1L;
123 | parkNanos = nanos;
124 | } else {
125 | long elapsed = System.nanoTime() - startTime;
126 | if (elapsed >= nanos) {
127 | removeWaiter(q);
128 | return state;
129 | }
130 | parkNanos = nanos - elapsed;
131 | }
132 | // nanoTime may be slow; recheck before parking
133 | if (state < COMPLETING)
134 | LockSupport.parkNanos(this, parkNanos);
135 | }
136 | else
137 | LockSupport.park(this);
138 | }
139 | }
140 |
141 | ```
142 |
143 | 这一堆看着是很长,发现注释只有一句话。
144 | `Awaits completion or aborts on interrupt or timeout.`
145 | 这个函数就干了这个事情, 等完成、等取消、等取消、等超时。 有人可能会说胡说,明明只有三个return。
146 | `throw new InterruptedException();`这不是还有一个抛出异常。
147 | 然后removeWaiter()又做了什么?
148 |
149 | ```java
150 | /**
151 | * Tries to unlink a timed-out or interrupted wait node to avoid
152 | * accumulating garbage. Internal nodes are simply unspliced
153 | * without CAS since it is harmless if they are traversed anyway
154 | * by releasers. To avoid effects of unsplicing from already
155 | * removed nodes, the list is retraversed in case of an apparent
156 | * race. This is slow when there are a lot of nodes, but we don't
157 | * expect lists to be long enough to outweigh higher-overhead
158 | * schemes.
159 | */
160 | private void removeWaiter(WaitNode node) {
161 | if (node != null) {
162 | node.thread = null;
163 | retry:
164 | for (;;) { // restart on removeWaiter race
165 | for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
166 | s = q.next;
167 | if (q.thread != null)
168 | pred = q;
169 | else if (pred != null) {
170 | pred.next = s;
171 | if (pred.thread == null) // check for race
172 | continue retry;
173 | }
174 | else if (!U.compareAndSwapObject(this, WAITERS, q, s))
175 | continue retry;
176 | }
177 | break;
178 | }
179 | }
180 | }
181 | ```
182 |
183 |
184 |
185 |
186 | ### FutureTask使用案例
187 |
188 | ```java
189 | ExecutorService service = Executors.newSingleThreadExecutor();
190 | FutureTask futureTask = new FutureTask<>(new Callable() {
191 | @Override
192 | public String call() throws Exception {
193 | return "futureTask say HelloWorld!!!";
194 | }
195 | });
196 | service.execute(futureTask);
197 | System.out.println(futureTask.get());
198 |
199 | ```
200 |
201 |
202 |
203 |
204 |
205 |
206 | ####参考资料
207 | [1] [Unsafe : http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/](http://mishadoff.com/blog/java-magic-part-4-sun-dot-misc-dot-unsafe/)
208 | [2] [synchronized 实现方式 : https://blog.csdn.net/qq_36520235/article/details/81176536](https://blog.csdn.net/qq_36520235/article/details/81176536)
209 | [3] [objectMonitor.hpp 源码 : https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/da3a1f729b2b/src/share/vm/runtime/objectMonitor.hpp](https://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/file/da3a1f729b2b/src/share/vm/runtime/objectMonitor.hpp)
210 | [4] [usafe https://blog.csdn.net/zyzzxycj/article/details/89877863](https://blog.csdn.net/zyzzxycj/article/details/89877863)
211 |
212 |
--------------------------------------------------------------------------------
/Framework/Handler.md:
--------------------------------------------------------------------------------
1 | ## Handler问题思考?
2 |
3 | 线程间通信机制是什么?怎么完成线程间通信的?
4 |
5 | 由什么组成?
6 |
7 | 调度策略是什么样的?消息循环机制,消息分发机制?
8 |
9 | 为什么这么设计?
10 |
11 |
12 |
13 |
14 |
15 | ## 1. 线程间通信机制
16 |
17 | 1. Handler 是典型的生产者-消费者模型。是线程之间进行通信的媒介。
18 |
19 | 2. 线程之间内存是不共享的,那么怎么完成的线程间通信?
20 |
21 |
22 |
23 | **设计通信机制的思路**:
24 |
25 | 进行消息封装 ---- 拿到目标线程句柄 --- 发送消息 --- 目标线程进行消息调度(优先级、异步、阻塞?)
26 |
27 |
28 |
29 | 实际上Handler也是按照这个思路进行,并有更多优秀的思考。比如消息池机制、消息屏障、IdleHandler、epoll等
30 |
31 |
32 |
33 | 首先看Handler的创建过程:
34 |
35 | ```java
36 | public Handler(@Nullable Callback callback, boolean async) {
37 | if (FIND_POTENTIAL_LEAKS) {
38 | final Class extends Handler> klass = getClass();
39 | // 是匿名类 或 成员类 或 局部类 ,但字段修饰符不是静态的时候, 有可能引起内存泄露。
40 | if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
41 | (klass.getModifiers() & Modifier.STATIC) == 0) {
42 | Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
43 | klass.getCanonicalName());
44 | }
45 | }
46 | // 获取Looper 如果当前线程没有Looper 抛出异常。
47 | // 1. 因为没有Looper 就执行不了下面mQueue的初始化
48 | // 2. 没有Looper将无法完成消息调度
49 | mLooper = Looper.myLooper();
50 | if (mLooper == null) {
51 | throw new RuntimeException(
52 | "Can't create handler inside thread " + Thread.currentThread()
53 | + " that has not called Looper.prepare()");
54 | }
55 | //这句。。 mQueue 是跨线程的句柄、
56 | // 如果不能初始化 也就不能传递消息
57 | mQueue = mLooper.mQueue;
58 | mCallback = callback;
59 | mAsynchronous = async;
60 | }
61 | ```
62 |
63 |
64 |
65 | 消息是怎么封装的?
66 |
67 |
68 |
69 | ```java
70 | public final class Message implements Parcelable {
71 | // 执行等待时长, 在MessageQueue中,以此为依据排序
72 | public long when;
73 | // 发送的数据
74 | /*package*/ Bundle data;
75 | // 目标线程的 Handler对象,用于发送 和 处理消息 跨线程
76 | /*package*/ Handler target;
77 | // Message Pool 消息池,回收和复用Message对象 MAX_POOL_SIZE = 50;
78 | private static Message sPool;
79 | }
80 | ```
81 |
82 |
83 |
84 | 消息怎么调度的? Looper.loop()
85 |
86 | ```java
87 | /**
88 | * Run the message queue in this thread. Be sure to call
89 | * {@link #quit()} to end the loop.
90 | */
91 | public static void loop() {
92 | // sThreadLocal.get();
93 | final Looper me = myLooper();
94 | if (me == null) {
95 | throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
96 | }
97 | // 从本地线程的ThreadLocal 中找到Looper对象, 并从其中拿到 MessageQueue
98 | // 那这个Looper对象是什么时候放进去的呢? 没错就是 Looper.prepare()
99 | // sThreadLocal.set(new Looper(quitAllowed));
100 | // 这也就是子线程不调用 prepare 就不能创建Handler、也不能运行Looper.loop()
101 | final MessageQueue queue = me.mQueue;
102 |
103 |
104 | for (;;) {
105 | // 如果没有消息这里不会返回
106 | Message msg = queue.next(); // might block
107 | // 返回null 这里会退出循环
108 | if (msg == null) {
109 | // No message indicates that the message queue is quitting.
110 | return;
111 | }
112 |
113 | logging.println(">>>>> Dispatching to " + msg.target + " " +
114 | msg.callback + ": " + msg.what);
115 |
116 | // 非空的消息 执行分发操作
117 | try {
118 | msg.target.dispatchMessage(msg);
119 | } finally {
120 |
121 | }
122 | logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
123 |
124 | // 放回消息池
125 | msg.recycleUnchecked();
126 | }
127 | }
128 |
129 | // Looper 并没有实际的调度,那么问题就在于这个next什么时候返回了。
130 | // 所以这个调度测量也就是next的返回策略。
131 | // MessageQueue.java
132 | Message next() {
133 | // Return here if the message loop has already quit and been disposed.
134 | // This can happen if the application tries to restart a looper after quit
135 | // which is not supported.
136 | // 消息不为空 但是Target是 null , 这说明什么问题?
137 | // 可以看下这个函数实现 private int postSyncBarrier(long when) {}
138 | // 在Post这个名字SyncBarrier的消息的时候没有赋值msg.target
139 | // 这就是我们所说的消息屏障。
140 | for (;;) {
141 | // 这里进入休眠,下次什么时候唤醒呢?
142 | // 1.
143 | // boolean enqueueMessage(Message msg, long when) {}
144 | // 这个函数里面nativeWake(mPtr) , 添加消息的时候会对messageQueue排序顺便会检查要不要唤醒
145 | // 这些条件(p == null || when == 0 || when < p.when) 满足,并且当前是阻塞状态,就会调用nativeWake(mPtr)
146 | // 这肯定不是唯一的唤醒方式,否则如果一直没有消息进来不是要死在这里了。。
147 |
148 | // 2.
149 | // Looper.cpp-->Looper::pollOnce()
150 | // 这里面使用了epoll机制, 超时返回。
151 | nativePollOnce(ptr, nextPollTimeoutMillis);
152 | // 消息屏障
153 | if (msg != null && msg.target == null) {
154 | // Stalled by a barrier. Find the next asynchronous message in the queue.
155 | do {
156 | prevMsg = msg;
157 | msg = msg.next;
158 | // 消息屏障存在的情况 就会搜索msgQueue中的isAsynchronous 异步消息,拿出来执行 。 直到队列末尾
159 | } while (msg != null && !msg.isAsynchronous());
160 | }
161 |
162 | // 到这基本流程就结束了
163 | // 但是还有一个IdleHandler机制
164 |
165 | }
166 |
167 | ```
168 |
169 | [nativePollOnce 函数讲解细节 ](https://www.kancloud.cn/alex_wsc/android-deep3/416265)
170 |
171 |
172 |
173 |
174 |
175 | ## 2. 三种消息类型
176 |
177 | 1. **同步消息**
178 | 2. **异步消息**
179 | 3. **消息屏障**
180 |
181 |
182 |
183 | ### 同步消息和异步消息
184 |
185 | Handler 发送的消息只有`Message`一种,怎么就出现了三种消息类型?
186 |
187 | 前面分析Handler创建的时候,可以看到最后一个参数是async,这里就注定这个Handler是发送出去同步消息还是异步消息。
188 |
189 | ```java
190 | public Handler(@Nullable Callback callback, boolean async) {
191 | /// async
192 | mAsynchronous = async;
193 | }
194 |
195 | // post 方法最终调用到的MessageQueue的入队方法。在这里设置了Message中一个属性 msg.setAsynchronous(true);
196 | private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
197 | long uptimeMillis) {
198 | // 这里必定会设置Target
199 | msg.target = this;
200 | msg.workSourceUid = ThreadLocalWorkSource.getUid();
201 | // 如果是异步的Handler,发出去的消息Message 就会带有 异步标记
202 | // 这个标记的 就区分出了两种消息, 同步消息和异步消息。
203 | // 什么区别呢?前面调度分析的时候,同步消息会被消息屏障阻塞, 而异步不会。
204 | if (mAsynchronous) {
205 | msg.setAsynchronous(true);
206 |
207 | }
208 | return queue.enqueueMessage(msg, uptimeMillis);
209 | }
210 | ```
211 |
212 |
213 |
214 | ### 消息屏障
215 |
216 | 好像只有这两种消息类型,消息屏障又是什么? 准确的说叫同步消息屏障,也就是说只会阻塞同步消息,通常是和异步消息一起使用。
217 |
218 | 消息屏障有什么特殊吗?
219 |
220 | ```java
221 |
222 | @TestApi
223 | public int postSyncBarrier() {
224 | return postSyncBarrier(SystemClock.uptimeMillis());
225 | }
226 |
227 | private int postSyncBarrier(long when) {
228 | // Enqueue a new sync barrier token.
229 | // We don't need to wake the queue because the purpose of a barrier is to stall it.
230 | synchronized (this) {
231 | final int token = mNextBarrierToken++;
232 |
233 |
234 | /// ******注意看这个消息的创建过程
235 | // 从消息池中拿到了这个消息对象之后,设置了when、 arg1 就加入到消息队列的单链表中了。
236 | // !!! 没设置 target 。 可以对比上面的 代码 msg.target = this;
237 | // 什么是消息屏障? Looper调度的时候,如果发现没有target的消息,那么就是消息屏障了
238 | final Message msg = Message.obtain();
239 | msg.markInUse();
240 | msg.when = when;
241 | msg.arg1 = token;
242 | // *********
243 |
244 | Message prev = null;
245 | Message p = mMessages;
246 | if (when != 0) {
247 | // 找到时间合适的那个节点
248 | while (p != null && p.when <= when) {
249 | prev = p;
250 | p = p.next;
251 | }
252 | }
253 | /// 加入进去
254 | if (prev != null) { // invariant: p == prev.next
255 | msg.next = p;
256 | prev.next = msg;
257 | } else {
258 | msg.next = p;
259 | mMessages = msg;
260 | }
261 | // 返回了一个 token 。 实际上就是一个计数
262 | // 删除的时候就据此token
263 | return token;
264 | }
265 | }
266 |
267 | ```
268 |
269 |
270 |
271 | 删除消息屏障的过程。
272 |
273 | ```java
274 | @TestApi
275 | public void removeSyncBarrier(int token) {
276 | // Remove a sync barrier token from the queue.
277 | // If the queue is no longer stalled by a barrier then wake it.
278 | synchronized (this) {
279 | Message prev = null;
280 | Message p = mMessages;
281 | // 找到 消息target为空 arg1 是 token的那个Message对象
282 | while (p != null && (p.target != null || p.arg1 != token)) {
283 | prev = p;
284 | p = p.next;
285 | }
286 | // 到末尾都没找到那么 就抛出异常了
287 | if (p == null) {
288 | throw new IllegalStateException("The specified message queue synchronization "
289 | + " barrier token has not been posted or has already been removed.");
290 | }
291 |
292 | // 从节点中删除
293 | final boolean needWake;
294 | if (prev != null) {
295 | prev.next = p.next;
296 | needWake = false;
297 | } else {
298 | mMessages = p.next;
299 | needWake = mMessages == null || mMessages.target != null;
300 | }
301 |
302 | // 将删除的节点回收,放入消息池中
303 | p.recycleUnchecked();
304 |
305 | // If the loop is quitting then it is already awake.
306 | // We can assume mPtr != 0 when mQuitting is false.
307 | if (needWake && !mQuitting) {
308 | // 有消息需要唤醒 nativePollOnce的阻塞 epoll_wait() 实现
309 | nativeWake(mPtr);
310 | }
311 | }
312 | }
313 | ```
314 |
315 |
316 |
317 | ## 3. 消息屏障的使用场景
318 |
319 | 在向Choreography订阅了VSync信号接收消息之后,VSync回调会触发重绘操作。
320 |
321 | 显然,这次界面刷新的优先级最高,因此使用了消息屏障以阻塞消息队列中不重要的同步消息。并创建一个异步刷新,加入到主线程Loop中的MessageQueue队列中。
322 |
323 | **ViewRootImpl.java**
324 |
325 | ```java
326 | // Post消息屏障到消息队列
327 | @UnsupportedAppUsage
328 | void scheduleTraversals() {
329 | if (!mTraversalScheduled) {
330 | mTraversalScheduled = true;
331 | // 设置消息屏障
332 | // 这里会返回Token , 删除的时候会以此为依据进行删除
333 | mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
334 | mChoreographer.postCallback(
335 | Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
336 | if (!mUnbufferedInputDispatch) {
337 | scheduleConsumeBatchedInput();
338 | }
339 | notifyRendererOfFramePending();
340 | pokeDrawLockIfNeeded();
341 | }
342 | }
343 |
344 | // 删除 消息屏障
345 | void unscheduleTraversals() {
346 | if (mTraversalScheduled) {
347 | mTraversalScheduled = false;
348 | // mTraversalBarrier 拿Token 去MessageQueue中删除屏障
349 | // 刪除消息屏障
350 | mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
351 | mChoreographer.removeCallbacks(
352 | Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
353 | }
354 | }
355 | ```
356 |
357 |
358 |
359 |
360 |
361 | ## 4. Handler 延时消息的实现
362 |
363 | ```java
364 | // 从开始加入消息开始看起
365 | // Handler 中两种消息延迟的方法
366 | // 1. 定时执行
367 | public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
368 | ...
369 | return enqueueMessage(queue, msg, uptimeMillis);
370 | }
371 | // 2. 延迟执行
372 | public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
373 | if (delayMillis < 0) {
374 | delayMillis = 0;
375 | }
376 | return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
377 | }
378 |
379 |
380 | // uptimeMillis 消息延迟执行的时间点
381 | public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
382 | MessageQueue queue = mQueue;
383 | if (queue == null) {
384 | RuntimeException e = new RuntimeException(
385 | this + " sendMessageAtTime() called with no mQueue");
386 | Log.w("Looper", e.getMessage(), e);
387 | return false;
388 | }
389 | // 在上节三种消息类型 中提到的queueMessage
390 | // queue.enqueueMessage 方法(msg, uptimeMillis);
391 | // 这里最终调用的是MessageQueue的 enqueueMessage 方法
392 | return enqueueMessage(queue, msg, uptimeMillis);
393 | }
394 |
395 | // 至此并没有找到为什么Handler 会延迟处理消息,只是在Message的when中增加了一个时间戳。
396 | // 那么就只剩消息队列,和消息调度环节了。
397 | ```
398 |
399 |
400 |
401 |
402 |
403 | ```java
404 | boolean enqueueMessage(Message msg, long when) {
405 |
406 | msg.markInUse();
407 | msg.when = when;
408 | Message p = mMessages;
409 | boolean needWake;
410 |
411 | //插入队列 两种情况
412 | // 1. 消息队列为空\待插入时间为0\第一条执行的when时间比待插入的时间更长
413 | if (p == null || when == 0 || when < p.when) {
414 | // New head, wake up the event queue if blocked.
415 | //将msg 插入到头部
416 | msg.next = p;
417 | mMessages = msg;
418 | // 插入到头部要唤醒
419 | needWake = mBlocked;
420 | // 2. 其他情况
421 | } else {
422 | // Inserted within the middle of the queue. Usually we don't have to wake
423 | // up the event queue unless there is a barrier at the head of the queue
424 | // and the message is the earliest asynchronous message in the queue.
425 | needWake = mBlocked && p.target == null && msg.isAsynchronous();
426 | Message prev;
427 | // 找到比当msg 执行时间更晚的消息
428 | for (;;) {
429 | prev = p;
430 | p = p.next;
431 | if (p == null || when < p.when) {
432 | break;
433 | }
434 | if (needWake && p.isAsynchronous()) {
435 | needWake = false;
436 | }
437 | }
438 | // 插入到查找到的消息位置
439 | msg.next = p; // invariant: p == prev.next
440 | prev.next = msg;
441 | }
442 |
443 | // 非头部不需要唤醒
444 | // We can assume mPtr != 0 because mQuitting is false.
445 | if (needWake) {
446 | nativeWake(mPtr);
447 | }
448 | }
449 | return true;
450 | }
451 | ```
452 |
453 |
454 |
455 |
456 |
457 | ## 5. Handler设计哪里好
458 |
459 | Handler 是Android的核心基础之一, 能够适应复杂的代码环境,被广泛的应用在Android系统代码中。
460 |
461 | 前面说到Handler设计策略是典型的生产消费者模型,调度策略巧妙的解决了生产消费模型中的执行顺序和优先级的问题。被广泛使用另一原因是**高效**,使用epoll机制,完成跨线程和超时唤醒,使Handler在消耗极少CPU资源的情况下准确的完成调度工作。
462 |
463 | 同时Handler设计中包含了很多的优化策略,比如消息池机制是比较常用的内存优化策略。再比如内存泄漏的检测,并且给出了友好的提示。同时Handler 提供了比较完善的监测机制,可以参考Looper 的代码进行详细的分析。
464 |
465 |
466 |
467 | ### 思考问题:
468 |
469 | 消息唤醒机制 eventFd
470 |
471 | Handler中的监控机制设计
472 |
473 |
--------------------------------------------------------------------------------
/Framework/IPC通信的方式汇总.md:
--------------------------------------------------------------------------------
1 | # Linux 中常用的跨进程通信方式
2 |
3 | ## 进程通信的一般步骤
4 |
5 | Client -- 序列化 --> 进程间通信机制 ---> 反序列化 --> Server
6 |
7 | 要求: 性能好、 使用方便、 安全
8 |
9 |
10 |
11 | ## Binder
12 |
13 | 1. 是CS架构,方便易用。
14 | 2. 仅需要一次内存拷贝
15 | 3. 安全,在内核态中添加安全认证识别机制
16 | 4. 组成: ServiceManager 、 Binder驱动 、Client 、 Services
17 |
18 |
19 |
20 |
21 |
22 | 5. 分层结构 Proxy、 BinderProxy、 BpBinder -- > Binder驱动 ----> BBinder --> Binder -->Stub
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 | 启动Binder机制过程:
31 |
32 | 1. 打开Binder驱动
33 | 2. 文件描述符进行mmap内存映射。
34 | 3. 启动Binder线程,注册到Binder驱动,进入Looper循环。
35 |
36 |
37 |
38 |
39 |
40 | ServiceManager Binder 驱动Id 是 0, 去其他方获取,需统一通过ServiceManager拿取。
41 |
42 |
43 |
44 | 这里和网络通信非常相像。
45 |
46 | ServiceMnager 是DNS解析。
47 |
48 | Binder协议是有确认机制的,类似TCP协议:
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | ## 管道
59 |
60 | 1. 半双工的通信方式,若想实现全双工,则需要一对描述符。pipe(fds)
61 | 2. 一般在父子进程使用
62 | 3. 数据量小的跨进程通信
63 |
64 | 两次拷贝
65 |
66 | 使用到管道的组件:
67 |
68 | Looper
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 | ## Socket
77 |
78 | 1. 全双工,可读可写
79 | 2. 在两个无亲缘关系的两个进程之间
80 | 3. 传输数据流不能太大
81 |
82 | 两次拷贝
83 |
84 |
85 |
86 | 使用Socket的组件
87 |
88 | Zygote --> AMS 通信
89 |
90 | ##
91 |
92 |
93 |
94 | ## 共享内存
95 |
96 | 1. 快 不需要多次拷贝
97 | 2. 进程之间无需亲缘关系
98 | 3. 数据流较大的传输
99 |
100 |
101 |
102 | 使用共享内存地方:
103 |
104 | MemoryFile -> SharedManery
105 |
106 | 创建文件描述符 --> 申请内存空间 --> Map 拷贝
107 |
108 |
109 |
110 | 图片传输相关
111 |
112 |
113 |
114 |
115 |
116 | ## 信号
117 |
118 | 1. 单向, 无确认机制
119 | 2. 只能发信号,不能传参数
120 | 3. 只需知道PID即可发信号,可群发信号。
121 | 4. Root权限,或UID相同可发信号
122 |
123 |
124 |
125 | 信号的使用:
126 |
127 | 杀进程:
128 |
129 | ```java
130 | public static final void killProcess(int pid) {
131 | sendSignal(pid, SIGNAL_KILL);
132 | }
133 | ```
134 |
135 | Zygote 关注子进程退出流程:
136 |
137 | ```c++
138 | static void SetSignalHandlers() {
139 | struct sigaction sig_chld = {};
140 | sig_chld.sa_handler = SigChldHandler;
141 |
142 | if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) {
143 | ALOGW("Error setting SIGCHLD handler: %s", strerror(errno));
144 | }
145 |
146 | struct sigaction sig_hup = {};
147 | sig_hup.sa_handler = SIG_IGN;
148 | if (sigaction(SIGHUP, &sig_hup, nullptr) < 0) {
149 | ALOGW("Error setting SIGHUP handler: %s", strerror(errno));
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 |
--------------------------------------------------------------------------------
/Framework/Provider跨进程通信.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/Provider跨进程通信.md
--------------------------------------------------------------------------------
/Framework/U-boot源码分析.md:
--------------------------------------------------------------------------------
1 | >Bootloader 完成了Linux系统启动前的硬件初始化,并将跳到C执行入口,进行firmware的初始化部分。这里主要分析汇编部分。
2 |
3 |
4 |
5 |
6 | U-boot 启动过程属于多阶段类型。第一阶段完成CPU体系结构初始化,通常由汇编完成。第二阶段实现较为复杂的功能如实现初始化硬件、内存映射、TFTP传输,串口调试,内核参数传递等,通常由C语言实现。
7 | ### 1. 第一阶段代码分析
8 | 第一阶段的源文件包括CPU初始化相关以及开发板初始化相关分别对应/cpu/arm920t/start.S和board/\*\*\*/lowlevel_init.S文件。
9 | #### 1.1. 硬件初始化
10 | 完成对CPU正常工作所必须初始化工作,如时钟、工作模式、MMU等。
11 |
12 | ```C
13 | reset:
14 | /*
15 | * 设置CPU 工作在超级保护模式(SVC32)
16 | */
17 | mrs r0,cpsr
18 | bic r0,r0,#0x1f
19 | orr r0,r0,#0xd3
20 | msr cpsr,r0
21 | ldr r0, =pWTCON /*关闭看门狗*/
22 | mov r1, #0x0
23 | str r1, [r0]
24 | .....
25 | bl cpu_init_crit /*跳转到该标签设置CPU寄存器MMU Cache等*/
26 | ```
27 |
28 | #### 1.2 初始化SDRAM控制器
29 | 准备Bootloader第二阶段代码RAM空间。
30 |
31 | ```C
32 | lowlevel_init:
33 | ldr r0, =SMRDATA /*13个寄存器值存放地址*/
34 | ldr r1, _TEXT_BASE
35 | sub r0, r0, r1 /*地址变换*/
36 | ldr r1, =BWSCON /* Bus Width Status Controller */
37 | add r2, r0, #13*4 /*SMRDATA 末尾地址*/
38 | 0: /*循环读取设置*/
39 | ldr r3, [r0], #4
40 | str r3, [r1], #4
41 | cmp r2, r0
42 | bne 0b
43 |
44 | /* everything is fine now */
45 | mov pc, lr
46 | .ltorg
47 | /* the literal pools origin */
48 | SMRDATA:
49 | .word ....
50 |
51 | ```
52 |
53 | #### 1.3 设置堆栈
54 | ```C
55 | stack_setup:
56 | ldr r0, _TEXT_BASE /*代码段地址之前作为堆栈 */
57 | sub r0, r0, #CFG_MALLOC_LEN/*留给 malloc 动态分配*/
58 | sub r0, r0, #CFG_GBL_DATA_SIZE /*存放全局变量 */
59 |
60 | #ifdef CONFIG_USE_IRQ
61 | sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
62 | /*IRQ和FIQ申请堆栈*/
63 | #endif
64 | sub sp, r0, #12 /* 留下12字节的abord异常空间*/
65 | ```
66 |
67 |
68 | #### 1.4复制Bootloader第二阶段程序到RAM空间
69 | ```C
70 | relocate: /* 将U-boot复制到RAM空间*/
71 | adr r0, _start /* 当前代码地址作为源地址给r0 */
72 | ldr r1, _TEXT_BASE/*代码段链接地址作为目标地址给r1 */
73 | cmp r0, r1 /* don't reloc during debug */
74 | beq clear_bss /*测试是否在RAM中调试,否则继续复制*/
75 | ldr r2, _armboot_start /*启动地址*/
76 | ldr r3, _bss_start /*BSS段起始地址 即 代码段结束地址*/
77 | sub r2, r3, r2 /* 代码段大小给 r2*/
78 | bl CopyCode2Ram /*Nand启动时(位于bord/boot_init.c )
79 | 跳转复制函数 r0: source, r1: dest, r2: size*/
80 | add r2, r0, r2 /* r2 <- source end address*/
81 | copy_loop: /*Nor flash 启动循环复制*/
82 | ldmia r0!, {r3-r10}/*copy from source address[r0] */
83 | stmia r1!, {r3-r10} /* copy to target address [r1] */
84 | cmp r0, r2 /*until source end addreee [r2] */
85 | ble copy_loop
86 | ```
87 |
88 | #### 1.5 跳转到C入口
89 |
90 | 跳转之前清除堆栈空间,然后PC指针跳转到/lib_arm/board.c中的start_armboot( )函数开始执行bootloader的第二阶段代码。
91 | ```C
92 | ldr pc, _start_armboot
93 | _start_armboot: .word start_armboot
94 | ```
95 |
96 |
97 | ### 2.第二阶段代码分析
98 | Bootloader第二阶段完成工作从lib_arm/board.c中的start_armboot( )函数开始执行,也即是第一阶段跳转到的地址。从这部分开始下面全是由C编写完成,分析起来较为容易,不做过多介绍,依次完成的主要工作:
99 |
100 | - size = flash_init ();
101 | - nand_init(); /* go init the NAND */
102 | - env_relocate (); /* initialize environment */
103 | - devices_init (); /* get the devices list going. */
104 | - jumptable_init (); /* 初始化跳转列表 */
105 | - console_init_r (); /* fully init console as a device */
106 | - enable_interrupts ();/* 中断使能 */
107 | - board_late_init ();
108 | - eth_initialize(gd->bd);/* 初始化网口 */
109 | - 在main_loop ()中死循环,等待用户交互。
110 |
111 | ```C
112 | for (;;)
113 | {
114 | main_loop ();
115 | }
116 | ```
--------------------------------------------------------------------------------
/Framework/UI线程的启动.md:
--------------------------------------------------------------------------------
1 | UI 线程和主线程相同?
2 |
3 |
4 |
5 | UI线程在Activity attach的时候被创建。
6 |
7 | ViewRootImpl 在onresume之后创建, 在没创建之前调用了。
8 |
9 |
10 |
11 | Activity UI线程就是主线程
12 |
13 | View UI线程是ViewRootImpl 创建所在的线程
14 |
15 |
--------------------------------------------------------------------------------
/Framework/Vsync原理.md:
--------------------------------------------------------------------------------
1 | ## 关键点:
2 |
3 | Vsync 的原理?
4 |
5 | Choreography的原理?
6 |
7 | UI刷新的大致流程,应用和SurfaceFlinger的通信过程?
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | ### UI绘制流程
20 |
21 | 1. requestLayout 重绘制
22 | 2. 创建了一个Callback 的traversal 的 Runnable。并增加了一个消息屏障
23 | 3. Choreography 向surfaceFlinger请求Vsync信号
24 | 4. Vsync 来的之后 会通过PostSyncEvent 回调给choreography
25 | 5. choreography -- >performTraversal
26 |
27 |
28 |
29 | // DisplayEventReceriver.java
30 |
31 |
32 |
33 | ## Vsync机制
34 |
35 | 1. Vsync生成机制
36 | 2. Vsync在SurfaceFlinger中的分发流程
37 | 3. Vsync信号的分发原理
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | //SurfaceFlinger.cpp --> init()
48 |
49 | // HWComposer
50 |
51 | //DispSyncSource
52 |
53 | // EventThread.cpp ---> threadMain
54 |
55 | //DisplayEventReceiver --> sendEvents -->fd
56 |
57 |
58 |
59 |
60 |
61 | ```java
62 | //MessageQueue 使用管道文件描述符
63 | void MessageQueue::setEventThread(android::EventThread* eventThread,
64 | ResyncCallback resyncCallback) {
65 | if (mEventThread == eventThread) {
66 | return;
67 | }
68 |
69 | if (mEventTube.getFd() >= 0) {
70 | mLooper->removeFd(mEventTube.getFd());
71 | }
72 |
73 | mEventThread = eventThread;
74 | mEvents = eventThread->createEventConnection(std::move(resyncCallback));
75 | mEvents->stealReceiveChannel(&mEventTube);
76 | mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
77 | this);
78 | }
79 | ```
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | ## 问题
92 |
93 | 丢帧一般什么原因引起的?
94 |
95 | --> 主线程有耗时操作,耽误了UI绘制。
96 |
97 |
98 |
99 | Android刷新频率60/s, 每隔16ms刷新一次?
100 |
101 | --> 不一定每次Vsync信号都会绘制, 应用端首先请求Vsync信号,Choreography才能收到Vsyn信号,才会绘制。
102 |
103 |
104 |
105 | OnDraw之后屏幕会立马刷新吗?
106 |
107 | --> 下次Vysc 才会刷新
108 |
109 |
110 |
111 | 如果界面没有重绘,还没每隔16ms重绘吗?
112 |
113 | --> 会刷新, 使用原buffer数据
114 |
115 |
116 |
117 | 如果在屏幕快要刷新的时候才去绘制会丢帧吗?
118 |
119 | -->没关系,Vsync信息来了就会刷新。
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
--------------------------------------------------------------------------------
/Framework/ashmem匿名共享内存.md:
--------------------------------------------------------------------------------
1 | ## Ashmem(Anonymous Shared Memory)
2 |
3 | Android 特有的内存共享机制,可以将指定的物理内存分别映射到各个进程自己的虚拟地址空间中,从而方便的实现进程间内存共享。
4 |
5 | 和Android Memory Killer 机制相似,实现由一个驱动完成(kernel/drivers/staging/android/ashmem.c).
6 |
7 |
8 |
9 | 同样的逻辑我们看下驱动的注册也就是Load的时候会调用的:
10 |
11 | ```c
12 | module_init(ashmem_init);
13 | module_exit(ashmem_exit);
14 |
15 | static int __init ashmem_init(void) {
16 | // 注册杂项设备驱动, 会在dev生成对应的文件节点 "dev/ashmem/"
17 | ret = misc_register(&ashmem_misc);
18 | // 通过register_shrinker注册到系统的shrinker_list中,这样在kswapd或者try_to_free_pages就有可能调到ashmem_shrinker
19 | // 和 Low Memory Killer 相似
20 | register_shrinker(&ashmem_shrinker);
21 | }
22 |
23 | ```
24 |
25 | ### 1 . 内存的映射
26 | 内存哪里来?
27 | 怎么实现进程间通信的?
28 | ashmem扮演什么角色?
29 |
30 | 注册杂项设备的时候,注册了这么一个处理对象。定义了驱动名称、设备号以及 一个处理函数指针结构体ashmem_fops;
31 |
32 | ```c
33 | static struct miscdevice ashmem_misc = {
34 | .minor = MISC_DYNAMIC_MINOR,
35 | .name = "ashmem",
36 | .fops = &ashmem_fops,
37 | };
38 | //fops ---> ashmem_fops
39 |
40 | static const struct file_operations ashmem_fops = {
41 | .owner = THIS_MODULE,
42 | .open = ashmem_open,
43 | .release = ashmem_release,
44 | .read = ashmem_read,
45 | .llseek = ashmem_llseek,
46 | .mmap = ashmem_mmap,
47 | .unlocked_ioctl = ashmem_ioctl,
48 | #ifdef CONFIG_COMPAT
49 | .compat_ioctl = compat_ashmem_ioctl,
50 | #endif
51 | };
52 | ```
53 |
54 | 其中包括了`open`、`release`基本操作,还包括了读取`mmap`以及`ioctl`操作。
55 |
56 |
57 |
58 | ```C
59 |
60 | ```
61 |
62 |
63 |
64 |
65 |
66 | ### 2. 内存的释放
67 | ```c
68 | //用于扫描释放需要释放的对象
69 | // 使用LRU算法管理内存, 释放不使用的内存, 直到释放到nr_to_scan为空
70 | static unsigned long
71 | ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
72 | {
73 | struct ashmem_range *range, *next;
74 | unsigned long freed = 0;
75 |
76 | /* We might recurse into filesystem code, so bail out if necessary */
77 | if (!(sc->gfp_mask & __GFP_FS))
78 | return SHRINK_STOP;
79 |
80 | if (!mutex_trylock(&ashmem_mutex))
81 | return -1;
82 | // 这里使用了LRU算法
83 | list_for_each_entry_safe(range, next, &ashmem_lru_list, lru) {
84 | loff_t start = range->pgstart * PAGE_SIZE;
85 | loff_t end = (range->pgend + 1) * PAGE_SIZE;
86 |
87 | range->asma->file->f_op->fallocate(range->asma->file,
88 | FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
89 | start, end - start);
90 | range->purged = ASHMEM_WAS_PURGED;
91 | lru_del(range);
92 | // 释放
93 | freed += range_size(range);
94 | if (--sc->nr_to_scan <= 0)
95 | break;
96 | }
97 | mutex_unlock(&ashmem_mutex);
98 | return freed;
99 | }
100 | ```
101 |
102 |
103 | ### 3. 应用实例 MemoryFile
104 |
--------------------------------------------------------------------------------
/Framework/image/Activity启动图1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Activity启动图1.png
--------------------------------------------------------------------------------
/Framework/image/Activity的显示原理.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Activity的显示原理.png
--------------------------------------------------------------------------------
/Framework/image/Binder分层结构.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Binder分层结构.png
--------------------------------------------------------------------------------
/Framework/image/Binder组成机制.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Binder组成机制.png
--------------------------------------------------------------------------------
/Framework/image/Binder请求协议.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Binder请求协议.png
--------------------------------------------------------------------------------
/Framework/image/Context继承关系.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Context继承关系.png
--------------------------------------------------------------------------------
/Framework/image/Service启动过程.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Service启动过程.png
--------------------------------------------------------------------------------
/Framework/image/SurfaceFlinger系统层显示原理.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/SurfaceFlinger系统层显示原理.png
--------------------------------------------------------------------------------
/Framework/image/Vsync事件分发流程.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Vsync事件分发流程.png
--------------------------------------------------------------------------------
/Framework/image/Vsync信号分发原理.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Vsync信号分发原理.png
--------------------------------------------------------------------------------
/Framework/image/Vsync信号流向.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Vsync信号流向.png
--------------------------------------------------------------------------------
/Framework/image/Vsync原理.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/Vsync原理.png
--------------------------------------------------------------------------------
/Framework/image/一般进程通信流程.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/一般进程通信流程.png
--------------------------------------------------------------------------------
/Framework/image/多APP和SurfaceFlinger连接示意图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/多APP和SurfaceFlinger连接示意图.png
--------------------------------------------------------------------------------
/Framework/image/屏幕双缓冲示意图.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/屏幕双缓冲示意图.png
--------------------------------------------------------------------------------
/Framework/image/管道使用方式.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/Framework/image/管道使用方式.png
--------------------------------------------------------------------------------
/Framework/zygote理解.md:
--------------------------------------------------------------------------------
1 | ### zygote作用
2 |
3 | 1. 启动SystemServer
4 | 2. 孵化应用进程
5 |
6 |
7 |
8 | ### zygote启动流程
9 |
10 | init.rc --> init进程 --> fork + execve ---> zygote
11 |
12 |
13 |
14 | 1. Native层准备进入JAVA层
15 |
16 | 创建JVM虚拟机-->注册JNI基础函数--> 进入java
17 |
18 | 2. Java层
19 |
20 | 预加载资源-- > 启动SystemServer(独立进程) --> Loop 循环等待接收Socket消息
21 |
22 | forkSystemServer
23 |
24 | ### zygote的工作原理
25 |
26 | 怎么启动进程,怎么进行通信
27 |
28 |
29 |
30 | 要点:
31 |
32 | 1. zygote的作用
33 | 2. 启动步骤
34 | 3. 怎么孵化进程? fork + execve / fork + handle
35 |
36 | 典型的Linux 写时拷贝机制的应用
--------------------------------------------------------------------------------
/Framework/应用Service启动流程.md:
--------------------------------------------------------------------------------
1 | ## Service启动过程
2 |
3 | ### 问题点
4 |
5 | 1. Service启动有几种方式, startService 和 BinderService
6 | 2. Service启动过程中主要流程有哪些?
7 | 3. 启动过程有哪些参与者,通信过程是怎么样的?
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | ### Binder Service原理
16 |
17 |
--------------------------------------------------------------------------------
/Framework/应用进程启动.md:
--------------------------------------------------------------------------------
1 | ## 问题描述
2 |
3 | 进程谁启动?
4 |
5 | 谁发起?
6 |
7 | 组件之间怎么进行通信的?
8 |
9 | 进程启动原理?
10 |
11 |
12 |
13 | ### 1. Linux 中进程启动方式
14 |
15 | ```java
16 | if(pid == fork() < 0){
17 | //error
18 | } else if (pid == 0) {
19 | //child Process
20 | execve()
21 | //--> 调用则独立资源
22 | // 不调用则共享 父进程资源
23 | } else {
24 | // parent process
25 | }
26 |
27 | ```
28 |
29 |
30 |
31 | ### 2. 什么时候触发进程启动
32 |
33 | 调用 StartProcessLocked启动
34 |
35 |
36 |
37 | 1. 应用启动组件会判断是否 创建了进程 ---> 调用IActivityManager ---> AMS
38 | 2. AMS 打开本地socket -> 发送参数列表 ----> Zygote 执行forkAndSpecialize
39 | 3. 执行 ActivityThread.main() 类名由AMS 通过参数列表传递
40 | 4. 应用进程向AMS注册,将自己Ibinder句柄, 启动Looper
41 | 5. 然后AMS启动应用组件 paddingServices。
42 |
43 |
44 |
45 | | | | |
46 | | ---- | ------------------------------------------------------------ | ---- |
47 | | AMS | --------- IApplicationThread 应用程序句柄 ------> | 应用 |
48 | | | <----------- IActivityManager AMSBinder句柄 ------- | |
49 |
50 | AMS中ProcessRecoder记录进程的状态信息。
51 |
52 |
53 |
54 | ProcessRecord != null
55 |
56 | ProcessRecord.thread != null
57 |
58 | --> attach(IApplicationThread) 注册到AMS中
59 |
60 |
61 |
62 | 组件进程启动完成后,启动组件。
63 |
64 | paddingServices列表,在应用启动过程中,在进程未注册到AMS之前,启动的组件入Service、Activity等会加入到paddingServices列表中。
65 |
66 |
67 |
68 |
69 |
70 | ### 3. 一个应用进程有多少线程?
71 |
72 | ```bash
73 | chiron:/ $ ps -T -p 24235
74 | USER PID TID PPID VSZ RSS WCHAN ADDR S CMD
75 | u0_a652 24235 24235 646 3944020 60272 0 0 S com.wgycs.hello
76 | u0_a652 24235 24240 646 3944020 60272 0 0 S Jit thread pool
77 | u0_a652 24235 24241 646 3944020 60272 0 0 S Signal Catcher
78 | u0_a652 24235 24242 646 3944020 60272 0 0 S ADB-JDWP Connec
79 | u0_a652 24235 24243 646 3944020 60272 0 0 S ReferenceQueueD
80 | u0_a652 24235 24244 646 3944020 60272 0 0 S FinalizerDaemon
81 | u0_a652 24235 24245 646 3944020 60272 0 0 S FinalizerWatchd
82 | u0_a652 24235 24246 646 3944020 60272 0 0 S HeapTaskDaemon
83 | u0_a652 24235 24247 646 3944020 60272 0 0 S Binder:24235_1
84 | u0_a652 24235 24248 646 3944020 60272 0 0 S Binder:24235_2
85 | u0_a652 24235 24254 646 3944020 60272 0 0 S Binder:24235_3
86 | u0_a652 24235 24260 646 3944020 60272 0 0 S Profile Saver
87 | u0_a652 24235 24262 646 3944020 60272 0 0 S Binder:intercep
88 | u0_a652 24235 24263 646 3944020 60272 0 0 S RenderThread
89 | ```
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/Framework/操作系统基础-通信机制-内存管理基础.md:
--------------------------------------------------------------------------------
1 | ## 一、Android 通信方式
2 |
3 |
4 |
5 | :bookmark_tabs:[IPC通信的方式汇总.md](./IPC通信的方式汇总.md)
6 |
7 |
8 |
9 | ## 二、操作系统内存管理基础
10 |
11 | ### 1. 内存地址映射
12 |
13 | Android 整体架构和实现机制如Binder、音频系统、GUI系统都与内存管理息息相关。内存管理主要涉及到以下几个方面:
14 |
15 | > 虚拟内存
16 |
17 | 计算机早期,内存资源是有限的,有些电脑的内存很小,可能无法将程序完整的加载到内存中运行。
18 |
19 | 于是想了一个办法,将外部存储器的部分空间作为内存的扩展,然后由系统按照一定的算法将暂时不用的数据放在磁盘中,用到时去磁盘中加载到内存。
20 |
21 | **按需加载**的思想,而且这一切步骤都由系统内核自动完成,对用户完全透明。
22 |
23 |
24 |
25 | 主要涉及到三种地址空间概念:
26 |
27 | 1. 逻辑地址
28 |
29 | 也称相对地址,是程序在编译后产生的地址。分为两部分,段选择子和偏移。这和硬件内存的设计思路是相通的,有片选信号和偏移组成。程序最终是运行在物理内存上的,对于有**段页式内存管理**的机器,由逻辑地址转换到物理内存还需要经过两个步骤。
30 |
31 | 【逻辑地址】---分段转换机制--->【先线性地址】---- 分页机制 ---> 【物理地址】
32 |
33 | 然而实际上Linux只实现了分页机制,没有分段。
34 |
35 | 2. 线性地址
36 |
37 | 逻辑地址转换后的产物,逻辑地址的段选择子中包含了段描述符,描述符记录了线性地址的基地址。基地址 + 线性偏移就得到了线性地址。
38 |
39 | 3. 物理地址
40 |
41 | 是真实的物理内存地址,物理地址是以固定大小的内存块为基本的操作对象,通常是4KB,称之为页。再说回前面的,对于虚拟内存,访问时,没有物理内存中访问到的页,被认为是缺失页,此时会触发中断,由操作系统去磁盘中置换相应的页到物理内存中。就此完成了虚拟内存的功能。
42 |
43 |
44 |
45 | > 内存分配与回收
46 |
47 | 对于操作系统而言,内存管理是其中重要组成部分。并且操作系统做的了,硬件无关性,且能动态分配和回收内存。对Android来说,针对**Native层**更多的要依靠开发者的人工管理,当然C++的智能指针是一个突破点。**Java层**的内存则是由JVM通过一整套系统的回收算法,统一管理。但是Java代码的编写依然需要严格的遵循使用规范,否则也可能引起内存泄漏等问题。
48 |
49 |
50 |
51 | ### 2. mmap(Memory Map)通信
52 |
53 | mmap可将某个设备或文件映射到应用进程的内存空间,实现进程的直接操作,节省了R/W的拷贝过程,提高了通信效率。比如Binder通信机制,在驱动层便是使用了**mmap**,将parcel对象映射到共同的地址,以完成进程间通信。
54 |
55 | 具体使用方式可以参见man文档
56 |
57 | ```bash
58 | man mmap
59 | ```
60 |
61 |
62 |
63 | ### 3. 写时拷贝技术(Copy On Write)
64 |
65 | 这是Linux中非常关键的技术,设计思想还是**按需创建**,多个对象起始时,共享某个资源,这时候这些对象不会拥有资源的拷贝,直到这个资源被某个对象修改。典型的使用场景是我们fork() 进程时,如果不调用execve() ,都会共享父进程的资源,调用之后子进程才会拥有自己的资源空间。
66 |
67 |
68 |
69 |
70 |
71 | ### 4. 内存回收机制 Android Memory Killer
72 |
73 |
74 |
75 | Android 系统在应用进程资源并不会立即被清除,这也就导致了一个问题,内存占用将成倍增加。怎么解决这个问题?
76 |
77 | 我们知道Linux在内核态实现自己的内存监控机制,**OOMKiller**。当系统内存占用达到临界值时,OOMKiller就按照优先级从低到高按照优先级顺序杀掉进程。
78 |
79 | 影响因素有:
80 |
81 | 1. 进程消耗的内存 |
82 | 2. CPU占用时间 | ------> oom_score //proc//oom_score
83 | 3. oom_adj |
84 |
85 |
86 |
87 | Android在**OOMKiller**基础上实现进一步的细分,并专门开发了一个驱动命名为 **Low Memory Killer** ( /drivers/staging/android/[:computer_mouse: Lowmemorykiller.c](http://androidxref.com/kernel_3.18/xref/drivers/staging/android/lowmemorykiller.c) )
88 |
89 |
90 |
91 | #### 4.1 Low Memory Killer 驱动加载过程
92 |
93 | ```C++
94 | static struct shrinker lowmem_shrinker = {
95 | .scan_objects = lowmem_scan,
96 | .count_objects = lowmem_count,
97 | .seeks = DEFAULT_SEEKS * 16
98 | };
99 |
100 |
101 | static int __init lowmem_init(void)
102 | {
103 | // 向内核线程kswapd 注册shrinker 监听回调
104 | // 当内存页低于一定阈值,就会回调lowmem_shrinker结构体里对应的函数
105 | register_shrinker(&lowmem_shrinker);
106 | return 0;
107 | }
108 |
109 | static void __exit lowmem_exit(void)
110 | {
111 | unregister_shrinker(&lowmem_shrinker);
112 | }
113 | //定义驱动加载和卸载时候的处理函数 lowmem_init
114 | module_init(lowmem_init)
115 | module_exit(lowmem_exit)
116 | ```
117 |
118 | 驱动加载时候,注册了处理函数lowmem_init() ,处理函数运行时向内核线程注册**lowmem_shrinker**结构体指针,我们可以看到 这个结构体中包含了两个函数指针,分别是`lowmem_scan` 和 `lowmem_count` ,这两个函数会在内核发现系统中空闲的页数低于阈值时候被回调。其中`lowmem_scan` 承载了驱动的关键任务**检测**和**回收**。
119 |
120 |
121 |
122 | #### 4.2 `lowmem_scan` 检测和回收逻辑
123 |
124 |
125 |
126 | ```c++
127 | // 代码比较长 这里筛检了主要逻辑
128 | static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
129 | {
130 | // 待检测的进程
131 | struct task_struct *tsk;
132 | // 需要回收的进程
133 | struct task_struct *selected = NULL;
134 | // 根据当前状态初始化必要的变量
135 | int array_size = ARRAY_SIZE(lowmem_adj);
136 | int other_free = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
137 | int other_file = global_page_state(NR_FILE_PAGES) -
138 | global_page_state(NR_SHMEM) -
139 | total_swapcache_pages();
140 |
141 | //1. RCU(Read-Copy Update)上锁
142 | rcu_read_lock();
143 | //2.遍历所有进程
144 | for_each_process(tsk) {
145 | struct task_struct *p;
146 | short oom_score_adj;
147 |
148 | if (tsk->flags & PF_KTHREAD)
149 | continue;
150 |
151 | p = find_lock_task_mm(tsk);
152 | if (!p)
153 | continue;
154 | //3.获取p的oom_score_adj 如果比最小阈值 还小, 那么暂时还不用杀;继续循环
155 | oom_score_adj = p->signal->oom_score_adj;
156 | if (oom_score_adj < min_score_adj) {
157 | task_unlock(p);
158 | continue;
159 | }
160 | tasksize = get_mm_rss(p->mm);
161 | task_unlock(p);
162 | //4.RSS <= 0 实际物理内存<=0; 不占内存 也暂时不杀
163 | if (tasksize <= 0)
164 | continue;
165 |
166 | if (selected) {
167 | if (oom_score_adj < selected_oom_score_adj)
168 | continue;
169 | if (oom_score_adj == selected_oom_score_adj &&
170 | tasksize <= selected_tasksize)
171 | continue;
172 | }
173 | //5.以上情况都没留住 那么锁定目标
174 | selected = p;
175 | selected_tasksize = tasksize;
176 | selected_oom_score_adj = oom_score_adj;
177 |
178 | }
179 |
180 | if (selected) {
181 | set_tsk_thread_flag(selected, TIF_MEMDIE);
182 | //6.发送 -9 SIGNAL 消息杀掉进程
183 | send_sig(SIGKILL, selected, 0);
184 | }
185 | //7.RCU(Read-Copy Update)解锁
186 | rcu_read_unlock();
187 | return rem;
188 | }
189 |
190 | ```
191 |
192 | 核心就是一个遍历进程的循环,将进程的内存占用状态和oom_score_adj分值进行相应的比较,当前系统状态下,分数够高就会被杀掉。
193 |
194 |
195 |
196 | #### 4.3 adj的维护
197 |
198 | `oom_score_adj`这个值我们看到是从进程内部取的,那么`adj`谁维护的呢?
199 |
200 | 在ActivityManagerService中有一个对象
201 |
202 | ```java
203 | // frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java
204 | OomAdjuster mOomAdjuster;
205 |
206 | ```
207 |
208 | 看名字是不是很有感? 没错就是这个类中维护了adj的状态,具体这里不分析了有兴趣可以取对应目录查看。
209 |
210 |
211 |
212 | | 名称 | 取值 | 解释 |
213 | | ---------------------- | ---- | -------------------------------------------------- |
214 | |UNKNOWN_ADJ|16|一般指将要会缓存进程,无法获取确定值|
215 | | CACHED_APP_MAX_ADJ | 15 | 不可见进程的adj最大值 |
216 | | CACHED_APP_MIN_ADJ | 9 | 不可见进程的adj最小值 |
217 | | SERVICE_B_AD | 8 | B List中的Service(较老的、使用可能性更小) |
218 | | PREVIOUS_APP_ADJ | 7 | 上一个App的进程(往往通过按返回键) |
219 | | HOME_APP_ADJ | 6 | Home进程 |
220 | | SERVICE_ADJ | 5 | 服务进程(Service process) |
221 | | HEAVY_WEIGHT_APP_ADJ | 4 | 后台的重量级进程,system/rootdir/init.rc文件中设置 |
222 | | BACKUP_APP_ADJ | 3 | 备份进程 |
223 | | PERCEPTIBLE_APP_ADJ | 2 | 可感知进程,比如后台音乐播放 |
224 | | VISIBLE_APP_ADJ | 1 | 可见进程(Visible process) |
225 | | FOREGROUND_APP_ADJ | 0 | 前台进程(Foreground process |
226 | | PERSISTENT_SERVICE_ADJ | -11 | 关联着系统或persistent进程 |
227 | | PERSISTENT_PROC_ADJ | -12 | 系统persistent进程,比如telephony |
228 | | SYSTEM_ADJ | -16 | 系统进程 |
229 | | NATIVE_ADJ | -17 | native进程(不被系统管理) |
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/Framework/添加系统服务.md:
--------------------------------------------------------------------------------
1 | 为什么要添加系统服务?
2 |
3 | 怎么让别人用?
4 |
5 | 哪些事情要干?
6 |
7 |
8 |
9 | ### 方便使用、开放接口、IPC
10 |
11 |
12 |
13 | 添加系统服务的时机:
14 |
15 | 1. 可以添加到 SystemServiceManager
16 | 2. 单开进程的系统服务 向 ServiceManager 注册
17 |
18 |
19 |
20 | 启动binder机制
21 |
22 | 打开binder机制 -- > 映射内存 mmp ,分配缓冲区 ---> 启动binder线程,进入 loop循环
23 |
24 |
25 |
26 | ## 怎么添加系统服务
27 |
28 | ### 服务端要做哪些事情?
29 |
30 | 1. 可以添加到 systemService中,或在init.rc 中添加启动脚本
31 | 2. 启用binder机制
32 | 3. 注册到ServiceManager
33 |
34 |
35 |
36 | ### 让应用方便获取要做哪些?
37 |
38 | //SystemServiceRegistry ---> StaticServiceFetcher
39 |
40 | //ContextImpl.java
41 |
42 | ```java
43 | @Override
44 | public Object getSystemService(String name) {
45 | return SystemServiceRegistry.getSystemService(this, name);
46 | }
47 | ```
48 |
49 |
50 |
51 | 其他操作:
52 |
53 | 编译配置,安全配置等
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | 系统服务和bind应用服务区别:
64 |
65 | | 名称 | 应用服务 | 系统服务 |
66 | | :------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
67 | | 启动方式 | Start或者bind都是由应用发起,并调用到AMS中,生成一个ServiceRecoder对象。 类加载--> 初始化上下文--> 生命周期方法。 | 在SystemServer中启动,准备初始化话工作,创建Binder对象, |
68 | | 注册方式 | 应用端向AMS发起注册是被动注册,由AMS主动请求Service,Service调用Attach注册到AMS中 | 注册到ServiceManager中,只有系统服务可以注册到ServiceManager |
69 | | 使用方式 | BindService 将 Service 和 AMS 建立Binder的双向通信机制 | 从ServiceManager中获取到Service的Binder代理对象 |
70 |
71 |
--------------------------------------------------------------------------------
/Framework/系统启动.md:
--------------------------------------------------------------------------------
1 | ## 1. Android有哪些服务进程
2 |
3 |
4 |
5 | zygote SystemServer ServiceManger 等
6 |
7 |
8 |
9 | 
10 |
11 | 图片源于:[sheldon_blogs](https://www.cnblogs.com/blogs-of-lxl/)
12 |
13 |
14 |
15 | ## 2. 系统进程是怎么启动的
16 |
17 | ### 2.1 Zygote 启动
18 |
19 | init进程 --> zygote
20 |
21 | Native 层 准备虚拟机, JNI函数,跳转到Java层
22 |
23 |
24 |
25 | //ZygoteInit.java -> main
26 |
27 | Java 层 加载系统资源 ---> 启动Systemserver ---> Socket Loop
28 |
29 |
30 |
31 | // 有socket common请求到来时
32 |
33 | //zygoteConnection -- > processOneCommand
34 |
35 | 读取解析参数 -- > Zygote.forkAndSpecialize() 创建进程 ----> handle 父进程和子进程的两次返回
36 |
37 |
38 |
39 | ### 2.2 SystemServer 启动
40 |
41 | Zygote.forkSystemServer()
42 |
43 | 创建Systemserver进程 ---> 处理启动细节 handleSystemServerProcess
44 |
45 |
46 |
47 | //ZygoteInit.zygoteInit()
48 |
49 | 1. RuntimeInit.commonInit(); 常规初始化
50 | 2. ZygoteInit.nativeZygoteInit(); 初始化Binder
51 | 3. RuntimeInit.applicationInit(classloader) 跳转到SystemServer java入口函数
52 |
53 |
54 |
55 | // SystemServer.java 初始化 main ----->>> run
56 |
57 | 1. 准备MainLooper
58 | 2. 创建 SystemServerManager 用于管理 后续创建的服务 用到类加载机制和反射
59 | 3. 分阶段启动服务, 分别有 bootstrapServices、CoreServices、OtherServices PID < 1000
60 | 4. 进入 Loop 循环
61 |
62 |
63 |
64 | 怎么解决服务之间的依赖:
65 |
66 | 分批启动
67 |
68 | 分阶段启动
69 |
70 |
71 |
72 | 发布到ServicesManager:
73 |
74 | ServiceManager.addService("package", m); -- >
75 |
76 | getIServiceManager().addService(name, service, allowIsolated, dumpPriority)
77 |
78 |
79 |
80 | 无论是独立进程的Service 或是 Binder 线程中的 服务, 都需要将服务注册到ServiceManager
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 说明 :star:
2 |
3 |
4 |
5 | 这里梳理了Android进阶的笔记,供奋斗在Android道路上的队友参考,我学习历程以及目标方向,其中涉及到的书籍和视频教程的笔记等内容,后续整理将逐步在此更新。
6 | ----
7 |
8 |
9 |
10 | [TOC]
11 |
12 |
13 |
14 | ----
15 |
16 | # 技能点 :star:
17 |
18 | # 1. 语言基础 :star2:
19 |
20 | ## 知识点 :bookmark_tabs:
21 |
22 | ### C/ C++
23 |
24 | ### NDK
25 |
26 | * JNI 注册流程
27 | * 动态注册和静态注册方式
28 |
29 | ### Java
30 |
31 | * Java虚拟机原理
32 | * [JVM与Dalvik/ART 区别与联系](./语言基础/JVM-Dalvik-Art.md)
33 | * [并发基础](./语言基础/java并发.md)
34 | * [线程安全](./语言基础/java并发.md)
35 | * 线程如何安全的停止保证代码的完整性
36 |
37 | ## 参考资料:books:
38 |
39 | * **《Java Concurrency In Practice》**
40 | * **《深入理解JAVA虚拟机》**
41 |
42 |
43 |
44 | # 2. 算法基础
45 |
46 | * 常用算法思想总结
47 | * 《编程珠玑》
48 | * 《剑指Offer》
49 |
50 |
51 |
52 | ## 参考资料
53 |
54 | * [Cyc2018 整理的算法笔记 :blue_book:](https://cyc2018.github.io/CS-Notes/#/notes/算法)
55 |
56 | * 《剑指Offer》
57 |
58 |
59 | # 3. 网络基础
60 |
61 | * **现任明教教主 -《*TCP*/*IP详解*卷1:协议》**
62 | * [1.网络通信原理TCP/IP 和 UDP :heavy_check_mark:](./网络基础/UDP.md)
63 | * 2.路由过程详解
64 | * 3.socket 通信TCP粘包和拆包
65 | * 4.Http 请求过程
66 |
67 |
68 |
69 | # 4. Android Framework :arrow_up_small:
70 |
71 | ## 参考资料 :books:
72 |
73 | * **罗升阳 ---《Android系统源代码情景分析 》**
74 | * **林学森 --- 《深入理解 Android内核设计思想》**
75 | * **慕课---风语: [剖析Framework 冲击Android高级职位](https://coding.imooc.com/class/chapter/340.html#Anchor)** (完成) --> [:notebook:](#Framework)
76 |
77 |
78 |
79 |
80 |
81 | ## 知识点 :bookmark_tabs:
82 |
83 | ### 操作系统基础
84 |
85 | * [Android 同步机制 :heavy_check_mark:](./Framework/操作系统基础-通信机制-内存管理基础.md)
86 | * [操作系统内存管理基础 :heavy_check_mark:](./Framework/操作系统基础-通信机制-内存管理基础.md)
87 | * [Ashmem匿名共享内存机制实现原理](./Framework/Ashmem匿名共享内存.md)
88 | * [Android Low Memory Killer :heavy_check_mark:](./Framework/操作系统基础-通信机制-内存管理基础.md)
89 | * [系统启动流程 :heavy_check_mark:](./Framework/Android启动机制汇总与对比.md)
90 | * [进程间通信机制原理和优缺点 :heavy_check_mark:](./Framework/IPC通信的方式汇总.md)
91 | * [线程间通信方式Handler深入理解 :heavy_check_mark: ](./Framework/Handler.md)
92 | * [Activity和Service的启动流程 :heavy_check_mark:](./Framework/Activity启动流程.md)
93 | * [ Activity 显示原理源码分析 :heavy_check_mark:](./Framework/Activity的显示原理.md)
94 | * UI体系相关内容,[Vsync机制](./Framework/Android系统显示原理-SurfaceFlinger.md)、surface原理等
95 | * Android 进程/线程的内存优化
96 | * [Android启动原理 :heavy_check_mark:](./Framework/系统启动.md)
97 | * 组件运行状态管理机制AMS
98 | * [对Context的理解:heavy_check_mark:](./Framework/Context.md)
99 |
100 | ### GUI系统
101 |
102 | * [渲染管理器 -- SurfaceFlinger原理代码分析详解](./Framework/Android系统显示原理-SurfaceFlinger.md) :heavy_check_mark:
103 | * 窗口管理器 -- WindowManagerService分析
104 | * View 框架分析
105 | * 输入事件管理组件 InputManagerService
106 | * [事件传递-WMS-IMS参考 ](https://blog.csdn.net/json_it/article/details/100715898)
107 |
108 | * PackageMangerService原理
109 | * 应用包管理
110 | * scheme原理
111 |
112 | ### 音视频系统
113 |
114 | * Android音频系统追溯
115 | * 系统播放器MediaPlayer/AwesomePlayer/NuPlayer
116 | * [相机架构组件 :camera: :heavy_check_mark:](https://source.android.google.cn/devices/camera?hl=zh_cn)
117 | * OpenGL图像渲染和优化
118 |
119 | ### 系统安全
120 |
121 | * Android安全机制解析
122 | * Android应用程序编译和打包
123 |
124 |
125 |
126 | # 5. Android优化进阶 :1st_place_medal:
127 |
128 | ## [绘制优化 :heavy_check_mark: ](./应用优化/卡顿优化.md)
129 |
130 | 1. **出现卡顿的原因**
131 | 2. **性能分析工具**
132 | 3. **优化方面和措施- 布局/绘制/刷新/动画/启动优化措施**
133 | 4. **监控方案**
134 |
135 | ## [启动优化 :heavy_check_mark:](./应用优化/启动优化.md)
136 |
137 | ## [内存优化:heavy_check_mark:](./应用优化/内存优化.md)
138 |
139 | 1. **内存管理机制**
140 | 2. **内存分析工具**
141 | 3. **优化方式总结**
142 |
143 | ## 存储优化
144 |
145 | 1. 常用存储方式适用场景 sharedPreference/SQLite/File/ContentProvider
146 | 2. 优化方案总结
147 |
148 | ## 稳定性优化
149 |
150 | 1. Crash检测手段 Java/ Native
151 | 2. 日志上报和分析
152 | 3. ANR疑难问题分析
153 | 4. 流程优化措施
154 |
155 | ## 耗电优化
156 |
157 | 1. 检测工具
158 | 2. 优化方案
159 |
160 |
161 |
162 | ## 网络优化
163 |
164 | ## 应用瘦身
165 |
166 |
167 |
168 |
169 |
170 | # 6. Android 音视频直播技术 :video_camera:
171 |
172 |
173 |
174 | | 流程 | 内容 |
175 | | ---- | ------------------------------------------------- |
176 | | 采集 | 音频:openSL ES
视频:surfaceTexture、 YUV |
177 | | 编码 | H264、H265、MediaCodec |
178 | | 传输 | TCP/UDP |
179 | | 解码 | H264、H265 |
180 | | 渲染 | OpenGL、默认渲染 |
181 |
182 |
183 |
184 | ## 参考资料 :books:
185 |
186 | * **《Android 音视频开发》**
187 | * 《FFmpeg从入门到精通》
188 |
189 | > ijkplayer [**:b:站 Github**](https://github.com/bilibili/ijkplayer)
190 | >
191 | > 基于ffmpeg的移动平台视频播放器
192 |
193 | 1. ijkplayer集成和使用
194 |
195 |
196 |
197 |
198 | >[google -- ExoPlayer :play_or_pause_button:](https://github.com/google/ExoPlayer)
199 | >
200 | >ExoPlayer is an application level media player for Android. ExoPlayer supports features not currently supported by Android’s MediaPlayer API, including DASH and SmoothStreaming adaptive playbacks.
201 |
202 |
203 |
204 |
205 |
206 | > FFmpeg 参考使用实例 [:a: FFmpegAndroid](https://github.com/xufuji456/FFmpegAndroid)
207 |
208 | ## 知识点 :bookmark_tabs:
209 |
210 | ### 音视频开发知识
211 |
212 | * [音视频基础原理 :heavy_check_mark:](./视频开发/音视频基础知识.md)
213 | * [常用的系统播放器 MediaPlayer (进行中...)](./视频开发/MediaPlayer.md)
214 | * 视频编解码网络传输原理
215 | * AAC音频格式和转换
216 | * H.264编码压缩算法
217 | * H. 264 视频数据格式解码
218 | * 硬件编解码H. 264
219 | * FFmpeg 跨平台开发
220 |
221 |
222 |
223 | ### webRTC
224 |
225 |
226 |
227 | ### OpenGL :triangular_flag_on_post:
228 |
229 |
230 |
231 |
232 |
233 | ## 图像处理技术
234 |
235 |
236 |
237 | ## 人脸识别方向
238 |
239 |
240 |
241 |
242 |
243 | # 7. 思想框架
244 |
245 | ## 思维提效
246 |
247 | * **《金字塔原理》**
248 | * 《番茄工作法》
249 |
250 |
251 |
252 | ## 哲学思想
253 |
254 | * [**《毛泽东选集》**](https://www.marxists.org/chinese/maozedong/index.htm)
255 | * [《矛盾论》:heavy_check_mark:](./思想指导/毛泽东选集/矛盾论.md)
256 | * [《实践论》:heavy_check_mark:](./思想指导/毛泽东选集/实践论.md)
257 | * [《战争和战略问题》:heavy_check_mark:](./思想指导/毛泽东选集/战争和战略问题.xmind)
258 | * [马克思社会辩证法思维导图 :heavy_check_mark:](./思想指导/马克思社会辩证法.md)
259 |
260 | ## 管理思想
261 |
262 | * 第五项修炼
263 | * 流程性组织
264 | * [如何进行高效时间管理:heavy_check_mark:](./思想指导/如何进行高效时间管理.md)
265 | * [结构化思维-金字塔原理](./思想指导/金字塔原理.md)
266 |
267 |
268 |
269 | ## 设计思想
270 |
271 | * **《软件构架实践》**
272 | * 弗农(美) --《实现领域驱动设计》
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 | # 笔记文件 :black_nib:
281 |
282 | ## 网络基础
283 |
284 |
285 | * [ARP_ICMP.md](./网络基础/ARP_ICMP.md)
286 | * [HTTP.md](./网络基础/HTTP.md)
287 | * [UDP.md](./网络基础/UDP.md)
288 |
289 |
290 | ## Framework(Android 9.0代码)
291 |
292 | * [Activity启动流程.md](./Framework/Activity启动流程.md)
293 | * [Activity的显示原理.md](./Framework/Activity的显示原理.md)
294 | * [Android启动机制汇总与对比.md](./Framework/Android启动机制汇总与对比.md)
295 | * [IPC通信的方式汇总.md](./Framework/IPC通信的方式汇总.md)
296 | * [Provider跨进程通信.md](./Framework/Provider跨进程通信.md)
297 | * [U-boot源码分析.md](./Framework/U-boot源码分析.md)
298 | * [UI线程的启动.md](./Framework/UI线程的启动.md)
299 | * [Vsync原理.md](./Framework/Vsync原理.md)
300 | * [zygote理解.md](./Framework/zygote理解.md)
301 | * [应用Service启动流程.md](./Framework/应用Service启动流程.md)
302 | * [应用进程启动.md](./Framework/应用进程启动.md)
303 | * [添加系统服务.md](./Framework/添加系统服务.md)
304 | * [系统启动.md](./Framework/系统启动.md)
305 |
306 | ## 应用优化
307 |
308 |
309 | * [AOP框架Aspectjx使用.md](./应用优化/AOP框架Aspectjx使用.md)
310 | * [内存优化.md](./应用优化/内存优化.md)
311 | * [单例模式.md](./应用优化/单例模式.md)
312 | * [启动优化.md](./应用优化/启动优化.md)
313 | * [绘制原理.md](./应用优化/绘制原理.md)
314 |
315 |
316 | ## 信息安全
317 |
318 | * [个人信息安全APP治理存在问题.md](./信息安全/个人信息安全APP治理存在问题.md)
319 |
320 |
321 |
322 | ## 工程杂记
323 |
324 | * [AOSP工程同步笔记](./工程杂记/获取AOSP工程步骤.md)
325 | * [计算机视觉在项目中应用](./工程杂记/计算机视觉在A3项目中应用.md)
326 |
327 |
--------------------------------------------------------------------------------
/信息安全/个人信息安全APP治理存在问题.md:
--------------------------------------------------------------------------------
1 | # 信息安全法律法规
2 |
3 |
4 |
5 | ## 一、法律法規责任庞杂
6 |
7 | 1. 民典法
8 |
9 |
10 |
11 | 矛盾:
12 |
13 | 个人信息保护 <-----> 数据产业发展
14 |
15 |
16 |
17 | 1. 法律责任:
18 |
19 | 民事责任 : 赔款、侵权
20 |
21 | 行政责任 : 处罚下架、无法更新
22 |
23 | 刑事责任: 爬虫等 罚金、坐牢
24 |
25 |
26 |
27 | 2. 责任越来越明确:
28 |
29 | 非法收集个人信息的民事责任:立即停止并删除相关信息。
30 |
31 | 补救信息。
32 |
33 | 数据链条长,发生数据侵权事件,怎么承担责任?
34 |
35 | 无法证明明确的责任方,将会出现连带责任。+==> 正在立法中
36 |
37 |
38 |
39 | 3. 监管方:
40 |
41 | 个人诉讼和公益诉讼的监管。
42 |
43 | 4. 近期出台的法律
44 |
45 | 《个人金融信息保护技术规范》、《信息安全技术个人信息安全规范》、《个人健康信息数据规范》等
46 |
47 |
48 |
49 | 国家大法
50 |
51 | --> 部门小法
52 |
53 | --> * 国标、行标 (最重要的影响因素)
54 |
55 |
56 |
57 | 
58 |
59 |
60 |
61 | ## 二、具体内容
62 |
63 |
64 |
65 | ### 2.1 告知同意
66 |
67 | 1. 告知目的、明示同意
68 |
69 | 2. 不得强制、不得误导
70 |
71 | 3. 部分信息不用告知入:
72 |
73 | 法定义务、国家安全、司法、生命财产安全等
74 |
75 |
76 |
77 | ### 2.2 个人生物信息
78 |
79 | 1. 生物信息不能随意采集
80 | 2. 不能随意存储和交换
81 |
82 |
83 |
84 | ### 2.3 汇聚融合
85 |
86 | 
87 |
88 |
89 |
90 | 是否改变了用户原授权的用途?--->否则 会有数据风险
91 |
92 | 数据提供方和提供方: 使用最小化原则,不能超范围处理。
93 |
94 | -----《个人信息安全》 7.3 、7.6
95 |
96 |
97 |
98 |
99 |
100 | ### 2.4 用户画像、个性化展示
101 |
102 | 大数据杀熟等反面案例
103 |
104 |
105 |
106 | ### 2.5 用户权利保障
107 |
108 | 1. 查询
109 | 2. 更正
110 | 3. 删除
111 | 4. 撤销授权
112 | 5. 注销账户
113 | 6. 获取个人信息副本
114 | 7. 投诉
115 |
116 |
117 |
118 | ### 2.6 委托处理、共享转让、共同控制、第三方介入合规
119 |
120 | 1. 不超出范围
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 | # APP治理
151 |
152 | ## 一、背景
153 |
154 | 互联网发展和移动设备飞快普及。APP占用 80% 的网络使用时间。
155 |
156 | 信息安全整体问题突出:
157 |
158 | 数据安全50以上存在5个以上信息安全问题
159 |
160 | 主要存在的问题:
161 |
162 | 
163 |
164 |
165 |
166 | ## 二、 环节问题出现分布
167 |
168 | 
169 |
170 |
171 |
172 | 
173 |
174 |
175 |
176 | 
177 |
178 |
179 |
180 | 1. 尽量仅在内存中存储用户信息,且进行加密。
181 | 2. 跳转第三方应用要进行提醒
182 |
183 |
184 |
185 | ## 三、主要问题
186 |
187 | 私自收集个人信息
188 |
189 | 过度索取权限
190 |
191 | 账号注销难
192 |
193 | 私自共享给第三方
194 |
195 | 不给权限不让用
196 |
197 | 强制用户使用定向推送功能
198 |
199 |
200 |
201 | ### 问题明细
202 |
203 |
204 |
205 | 
206 |
207 | 
208 |
209 | 
210 |
211 | 
212 |
213 | 
214 |
215 | 
216 |
217 | 图片源于张正忠分享
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 | # 移动应用数据安全管理
226 |
227 | 中国信通院 -- 崔伟男
228 |
229 | ## 一、现状
230 |
231 | 网信办、工信部等多部门颁布相关管理规定,从准入管理、资源管理、行为管理三方面加强移动APP监管。推动行业健康有序发展,信通院做了很多工作,从管理层到实施数据始终在人的操控下进行,提高数据操控者素质和建立整体可控、可查、可防御的数据制度安全体系。
232 |
233 |
234 |
235 | ## 二、数据安全管理原则
236 |
237 | 1. 坚持保障数据安全与发展并重
238 | 2. 鼓励研发数据安全保护技术
239 | 3. 积极推进数据资源开发利用
240 | 4. 保障数据依法有序自由流动
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
--------------------------------------------------------------------------------
/信息安全/侵权占比.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/侵权占比.png
--------------------------------------------------------------------------------
/信息安全/信息安全生命周期.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/信息安全生命周期.png
--------------------------------------------------------------------------------
/信息安全/内部制度建立.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/内部制度建立.png
--------------------------------------------------------------------------------
/信息安全/处理方向.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/处理方向.png
--------------------------------------------------------------------------------
/信息安全/数据汇聚融合.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/数据汇聚融合.png
--------------------------------------------------------------------------------
/信息安全/未公开收集使用权限.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/未公开收集使用权限.png
--------------------------------------------------------------------------------
/信息安全/未按法律规定.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/未按法律规定.png
--------------------------------------------------------------------------------
/信息安全/未明示收集个人信息目的.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/未明示收集个人信息目的.png
--------------------------------------------------------------------------------
/信息安全/未经同意使用.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/未经同意使用.png
--------------------------------------------------------------------------------
/信息安全/未经同意提供三方.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/未经同意提供三方.png
--------------------------------------------------------------------------------
/信息安全/现状1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/现状1.png
--------------------------------------------------------------------------------
/信息安全/现状2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/现状2.png
--------------------------------------------------------------------------------
/信息安全/现状3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/现状3.png
--------------------------------------------------------------------------------
/信息安全/违反必要原则.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wgycs/CSAndroid-Notes/41acfdac910a1a8328303391e62b722240a32d52/信息安全/违反必要原则.png
--------------------------------------------------------------------------------
/工程杂记/Visual VM使用说明.md:
--------------------------------------------------------------------------------
1 | # Visual VM
2 |
3 |
4 | ### Visual VM安装
5 | Visual VM 工具在JDK目录中可以找到,如`jdk1.8.0_65\bin`目录下。
6 |
7 |
8 | ### Visual VM插件安装
9 |
10 |
11 | ### 插件安装报错
12 |
13 | `无法连接到visualVM插件中心2,因为https://visualvm.github.io../updates.xml.gz`
14 |
15 | 在visualVM 工具->插件选项中,点击可用插件,检查最新版本时,出现无法连接到visualVM插件中心2,因为https://visualvm.github.io../updates.xml.gz
16 |
17 | #### 解决步骤:
18 | 1.打开网址:https://visualvm.github.io/pluginscenters.html
19 | 2.在右侧选择JDK版本
20 | 3.选择之后会打开相应的插件中心,复制CatalogURL
21 | 4.打开visualVM,工具->插件->设置,然后把刚才的网址粘贴进去。
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | ### 参考资料:
30 | https://www.cnblogs.com/baby123/p/11551626.html
--------------------------------------------------------------------------------
/工程杂记/cmake基础语法.md:
--------------------------------------------------------------------------------
1 | [TOC]
2 |
3 |
4 | [官方Cmake语法原文](https://cmake.org/cmake/help/latest/manual/cmake-language.7.html#organization)
5 | ## Cmake工具
6 | - cmake 交叉编译系统生成工具
7 | - ctest 自动化测试工具
8 | - cpack 自动化打包工具 可以生成各种格式的安装程序和源码包
9 |
10 |
11 |
12 | ## Cmake 语法
13 | 相比于make的规则,输入文件有指定的命名规则即为`Makefile`. \
14 | Cmake 输入文件是以Cmake语法编写的,以`CmakeLists.txt命`名或以`.cmake`扩展名的文件.为了尽可能的跨平台使用的7-bit ASCII 字符编写,使用UTF-8编码。
15 |
16 | ### 1. 多级依赖目录树和配置文件配置
17 | - 使用`add_subdirectory()`函数,添加同样包含`CmakeList.txt`,Cmake进行编译时,会在build相应的目录下生成输出文件.
18 | - 通用资源或配置可以添加`