├── .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 | Activity启动图1 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 | image-20200513213944396 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 | **![img](https://pic4.zhimg.com/80/89487fbeaa923180f2ff8767605505aa_720w.jpg)** 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 | ![img](https://imgconvert.csdnimg.cn/aHR0cDovL3VwbG9hZC1pbWFnZXMuamlhbnNodS5pby91cGxvYWRfaW1hZ2VzLzM5ODU1NjMtZjJmZTM3NzViZDI2NzhjMi5wbmc?x-oss-process=image/format,png) 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 | ![img](https://imgconvert.csdnimg.cn/aHR0cDovL3VwbG9hZC1pbWFnZXMuamlhbnNodS5pby91cGxvYWRfaW1hZ2VzLzM5ODU1NjMtZTUzM2IwY2RkN2ZjYTM1OS5wbmc?x-oss-process=image/format,png) 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 |
没有VSync信号
25 | 26 | **2. 有VSync信号正常情况** 27 | 28 | 有VSync信号 29 | 30 | **3. 有VSync信号但GPU处理能力不足,16ms内未渲染完成** 31 | 32 | 有VSync信号GPU处理能力不足 33 | 34 | 35 | **4. 三缓冲机制对情况三的优化** 36 | 37 | 有VSync信号处理不及时情况下的优化 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 | ![SurfaceFlinger系统层显示原理](image\SurfaceFlinger系统层显示原理.png) 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 | ![vysnc](./image/Vsync信号流向.png) 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 | ![多APP和SurfaceFlinger连接示意图](image/多APP和SurfaceFlinger连接示意图.png) 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 | ![Context继承关系](image/Context继承关系.png) 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 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 | ![img](https://img2018.cnblogs.com/blog/821933/201907/821933-20190730111306166-2128331293.png) 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 | ![image-20200529142339217](信息安全生命周期.png) 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 | ![image-20200529143445899](数据汇聚融合.png) 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 | ![image-20200529144920039](处理方向.png) 131 | 132 | 133 | 134 | 内部管理制度: 135 | 136 | 137 | 138 | ![image-20200529145014196](内部制度建立.png) 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 | ![image-20200529145535531](侵权占比.png) 163 | 164 | 165 | 166 | ## 二、 环节问题出现分布 167 | 168 | ![image-20200529145705170](现状1.png) 169 | 170 | 171 | 172 | ![image-20200529145723594](现状2.png) 173 | 174 | 175 | 176 | ![image-20200529150017765](现状3.png) 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 | ![image-20200529151053227](未公开收集使用权限.png) 206 | 207 | ![image-20200529151203012](未明示收集个人信息目的.png) 208 | 209 | ![image-20200529151304963](未经同意使用.png) 210 | 211 | ![image-20200529151347687](违反必要原则.png) 212 | 213 | ![image-20200529151539686](未经同意提供三方.png) 214 | 215 | ![image-20200529151505471](未按法律规定.png) 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 | - 通用资源或配置可以添加`