Android 那些跨不过去的门槛 ，以前欠下的账早晚是要还的
截止发稿时 Room 的最新版本为 2.3.0-alpha04，这个版本无法在 Apple Silicon 中使用。看了一下 Room 的 Sqlite Jdbc 版本为 3.25.2。然后查看了一下 Sqlite Jdbc Releases 他是在 3.32.3.3 版本中开始兼容 Apple Silicon M1 芯片的。我们可以自己单独引用 Jdbc，只要引用的版本高于 3.32.3.3 即可解决这个问题。implementation("androidx.room:room-runtime:2.3.0-alpha04") { exclude(group:'org.xerial') } kapt("androidx.room:room-compiler:2.3.0-alpha04"){ exclude(group:'org.xerial') } implementation("androidx.room:room-ktx:2.3.0-alpha04"){ exclude(group:'org.xerial') } implementation 'org.xerial:sqlite-jdbc:3.34.0'
名词解释内核（Kernel）：管理硬件资源，向应用程序提供所需的硬件资源。系统调用：是内核提供的应用程序与内核的沟通桥梁。POSIX（Portable Operating System Interface of UNIX）：是操作系统提供的应用程序与操作系统的沟通桥梁。它是统一的标准许多系统都支持。C 标准库：因为操作系统的使用的库通常是用 C 语言提供的。所以 C 标准库是封装了很多方便我们系统或应用程序开发的函数，当然其中也包含对 系统调用 的封装。守护进程：他是在系统里运行的后台任务，此类程序会被以进程的形式初始化。不会接受用户的直接操作。ELF 文件：(Executable and Linkable Format)是一种用于可执行文件、目标文件、共享库和核心转储的标准文件格式。目前常见的 Linux、 Android 可执行文件、共享库（.so）、目标文件（ .o）以及 Core Dump 文件均为此格式。Android 官方网站的 Android 系统结构图首先最底层是内核内核主要作用是管理硬件，也要保障安全等功能。所以其中包含硬件的驱动，以及硬件的工作方式和模型。比如：给 CPU 定义出进程，线程等任务调度的工作逻辑。内存的工作方式等。HAL 安卓独有的一层提供了一层标准的 API ，这样底层硬件如何变化上层将不再关心。这一层相当于充当适配的一层，隔离开上下层的变化。Native C/C++ 库层其中各种第三方库的 ELF 可执行文件，包含守护进程，C 标准库，空的 Android 应用进程。Android 引入了很多功能的 ELF 可执行文件，然后通过守护进程的方式运行起来。比如 Wi-Fi 功能的可执行文件，蓝牙的可执行文件等等，最后都是以守护进程的方式在后台运行的。这一层干的事比较多可以分为二层，首先这第一层提供的 C 标准库和 Android 系统需要用到的很多 Linux 和独有的守护进程和各种第三方库的 ELF 可执行文件。比如系统可能需要联网功能的守护进程，通信守护进程，GPS 守护进程，声音守护进程等等，这里可以根据系统功能进行精简或添加。Android 用了很多第三方的库和手段来保持 Android 系统正常和稳定的运行和应用的可执行性，到这一层为止基本上 Google 已经提供了一套没有 UI 环境的低功耗版 Linux 系统的方案，使其可以运行在各种微型或小型设备上。基本的低功耗 Linux 系统已经有了，剩下的就可以根据自己的想法来定义系统生态和玩法了。Android 的玩法是想使用 Java 语言作为应用开发语言，所以 Android 需要提供一套 JVM 虚拟机和一些基础服务。所以 Android 又垒了第二层 Android 使用原生代码实现了 Android 的运行时（Android Runtime）。Android Runtime 中包含了 Android 应用程序运行的基本库、基础服务和一台 JVM 虚拟机来运行 Java。Java 库Google 的玩法是在该层通过 Java 语言编写了 Android OS 的系统的基础功能的 API 、服务和各项可视化的系统功能。比如为了统一应用开发标准，定义基本的 Android 应用运行逻辑，抽象出了四大组件供开发者快速开发。以及系统运行的各项基础服务，底层的通信，GPS，摄像头等等守护进程的 Java 封装。然后在之上又做了一些系统级的应用界面。应用层使用 SDK 和 C 标准库开发的应用，每个应用其实都是一个或多个 Android Runtime 的实例进程，把 Java 的代码在虚拟机中运行。个人理解的 Android 操作系统官方 Android 源码结构图
root 文件系统目录或文件功能解释acctacct cgroup（control group）的挂载点apexAndroid 10 模块化了一些Android系统组件，使其能在 Android 大版本升级之外进行独立升级，即系统组件模块化（Modular System Components）。这些模块化的系统组件打包到一起，可以通过 OTA 方式推送给终端用户进行升级。cache缓存的大小被限制为这个分区的大小。d/sys/kernel/debug 的一个符号链接。data存放用户安装的软件以及各种数据。default.prop其中记录的是编译时 /build/core/main.mk 中 ADDITIONAL_DEFAULT_PROPERTIES 变量中的值， init 将根据它（的内容）去加载其他系统范围内的属性文件（property）。加载只读的属性文件有利于强制执行安全保护devtmpfs 文件系统的挂载点，定义了应用程序可用的设备。/dev/cpuctl 目录是 cpuctl 控制组的挂载点，使用 cgroup 伪文件系统。etc/system/etc 的一个符号链接。与 Linux 功能一致，存放配置文件init处理 init.rc 文件的一个二进制程序。init.rc 文件引入其他 init.*.rc 文件。Android 启动时，内核会在启动进程的最后运行 init 程序。init.rc 文件值得一读，它告诉我们一些 Android 设备配置的事情。由于 Android 不支持 /etc/sysctl.conf，所以 /proc/sys/kernel 参数的更新就成为了 init.rc 文件的一部分。除非你对 Linux 内核的内部工作机制有一个好的理解，最好不要修改这些参数。对 /dev/cpuctl 的参数也是一样的道理。mnt除了挂载内部和外部SD卡，这个目录还是其他文件系统的挂载点。/mnt/asec 目录是一个 tmpfs 文件系统的挂载点，它是 Android 安全机制的一部分。/mnt/obb 目录是一个 tmpfs 文件系统的挂载点，它用来存储应用程序文件超出 50MB 后的扩展文件。/mnt/secure 目录是 Android 安全机制的另外一个组件。你也可以看到一个或多个 USB 设备的挂载点。procprocfs 文件系统的挂载点，用来提供对内核数据结构的访问。sbin比标准 Linux 发行版中的 /sbin 目录小很多，但它确实包含了几个重要守护进程的二进制文件。sdcard/mnt/sdcard 的一个符号链接。storage外部SD卡所在目录syssysfs 伪文件系统的挂载点，sysfs 伪文件系统是内核的设备对象结构的反映。这个目录下有很多信息，但它需要理解内核设备模型。简而言之，这些目录表示内核对象，而文件是这些对象的属性。system这个目录下就是你通常在标准 Linux 发行版中 root 目录下看到的目录。这些目录包括 bin、etc、lib、usr和xbin。ueventd.rc这些文件定义了/dev目录的配置规则。vendor/system/vendor 的一个符号链接。init.rc系统初始化脚本。同样里面会引用 init.*.rc 文件。/system 文件系统存放所有谷歌或厂商提供的 Android 组件的地方，该文件系统是以只读方式 mount 的，主要是考虑了稳定性和安全性。目录或文件功能解释app存放系统应用，一般是系统或厂商自带应用。apexAndroid 10 模块化了一些Android系统组件，使其能在 Android 大版本升级之外进行独立升级，即系统组件模块化（Modular System Components）。这些模块化的系统组件打包到一起，可以通过 OTA 方式推送给终端用户进行升级。bin存放二进制可执行文件 ： 其中既有多个守护进程的二进制可执行文件，也有一些命令行 shell 的二进制可执行文件。一般是系统自带的。（大多数指向 looIbox)etc各种系统组件的配置文件fonts存放各种字体文件framework存放 Android 的框架（framework ） ， 各个 framework 会被存放在各自对应的 .jar 文件中lib存放运行时库文件，也就是原生的 .so (ELF shared object），在 Android 中，这个目录扮演了和正常 Linux 系统中的 /lib 目录一样的角色。media存放铃声、系统提示声的文件夹。xbin存放用途特殊的、正常操作过程不需要使用的二进制文件，一般是系统管理工具。build.prop编译过程中生成的属性配置文件。priv-app存放特权的 Appusr支持文件，比如 unicode 映射文件，设备和键血的键盘布局文件等vendor专门存放第三方厂商提供的文件，但是一般厂商都是直接放到 /system 目录下的 /bin、/lib 当中。lost+ found在对 /system 进行 fsck 操作时自动生成的目录 。 通常是空的（除非系统曾经崩渍过）。新版本 Android 不存在这个目录了。/system/bin 文件系统/system/bin 目录中含有 Android 使用的各种原生可执行文件，此外，它也是存放各种调试工具的地方。具体来说，这些二进制可执行文件可以被分成 5 类。用来提供服务的二进制可执行文件： 这类二进制可执行文件都是在系统运行过程中由 /init 调用的， 它们的调用路径会被写进 /init 使用的 rc 文件中。调试工具： 被归入这一类 的是一些用于调试的原生二进制可执行文件。UNIX 命令： 为了让 shell 用户也能在 Android 上玩 ， UNIX 命令部被封装在一个单独的二进制可执行文件 /system/bin/toolbox 中。busybox 是嵌入式系统中常见的多合一工具集，而 toolbox 则是它在 Android 中的定制版。调用 Dalvik 的脚本（upcall script）：这些调用 Dalvik 的脚本让用户通过 shell 与 Dalvik 运行时框架交互，这多半是为了进行调试。厂商定制的二进制可执行文件：从本质上讲，这类二进制可执行文件可以完全由厂商控制，但是这类二进制可执行文件通常都是些提供服务的程序或调试工具。/system/bin 用来提供服务的二进制可执行文件目录或文件功能解释app_process用户 App 的宿主进程， Zygote〔及其他所有用户 App）都是这个二进制可执行文件的实例，app_process 它是由 DalvikVM /ART 初始化的。applypatch在 OTA 升级的过程中使用 根据脚本来应用补丁bootanirnation当图形界面子系统（surfaceflinger）加载时，播放 Android 的启动动画。clatd1Pv4-1Pv6 地址的转换器dalvikvrn用于启动一个 Dalvik 虚拟机的实例debuggerd在系统崩溃时产生 tombstone， 也可以和一个远程 GDB 相连接dnnserver第二方数字版权管理（ DRM, Digital Rights Management ）模块的宿主地程clnsmasq伪 DNS 服务：在设备对外提供 Wi-Fi 热点服务时，提供 DNS 代理服务hostapdWi-Fi 热点守护进程的二进制可执行文件：在设备对外提供 Wi-Fi 热点服务时提供一个热点keystoreAndroid 的密码存储和管迎服务linkerAndroid 的运行时链接器。mdnsd组描 DNS (multicast DNS）的守护进程mecliaserver音频、视频的录制、回放mtpd用以支持 PPP/L2TPnetd用来管理网卡、防火墙等pppd点对点协议的守护进程，在使用 VPN 时才需要使用它racoon提供对 VPN 支持rlid无线界面层（Radio Interface Layer）守护进程：主管一切与电话相关的服务sdcardSDCard 守护进程，实现了 SD 卡文件系统，通过 FUSE 模拟多用户权限设置sensorserv1ceSensor hub：并发读取各个传感器servicemanager提供了服务的注册和查找功能surfaceflinger它的功能是画出图形界丽的样子，并把它们加载到 framebuffer 中voldVolume 守护进程：用来 mount/unmount 文件系统，也有文件，系统的解密功能uncrypt解密文件系统（在 recovery 前使用）wpa_supplicantwpa_supplicant 适配层（wireless protected access supplicant）：提供 Wi-Fi 和 Wi-Fi P2P 的客户端支持sqlite3数据库功能dexdumpDEX 文件 dump 工具，也能 dump 文件头和字节码tcpdump网络抓包工具。抓取到的数据文件可以用 Wireshark 打开strace系统调用 trace 工具。使用 Linux ptrace(2)系统调用 。 强大的 trace 和逆向工程工具，往往能给你带来惊喜showmap显示进程内存分配情况（数据取自 /proc/pid/maps)procrank该程序的功能与 librank 互补 ， 它会逐个进程地给出各个进程中 VSS/RSS/PSS/USS 的使用情况统计信息procmem显示进程内存使用情况统计信息（数据取自 /proc/pid/status )ncNetcat ， 分析 TCP 和 UDP 时的瑞士军刀librank逐个给出各个共享内存区域在各个进程中的使用情况，主要给出 VSS/RSS/PSS/USS 信息/system/bin 调试工具目录或文件功能解释adbAndroid 调试桥（客户端）asanwrapperAddress Sanitizer：内存淄出检测工具，它是个第三方调试工具atraceAndroid tracetool：使用 Linux 的 ftrace 来调试和跟踪程序的执行过程bdtBlueDroid ( Android 中的蓝牙）测试 Appblkid用来显示各个分区的 GUIDdex2oatDEX 到 ART 的转换工具，用于取代 dexopt。dexoptDEX 优化工具。dumpstate能与其他几个有用的工具（ps、dumpsys 等〕一起使用的元工具，用于抓取系统状态的调试快照。Dumpsys服务转储工具：它能去连接 Android 的各个服务，请求调用服务中的 Dump() 方法，以提供大量的调试信息e2fsckF2FS 文件系统的文件系统完整性检测工具。fsck_msdosvFAT 文件系统的文件系统完整性检测工具。fsck.f2fsExt2/3/4 文件系统的文件系统完整性检测工具。gdbserverGDB 服务端：启动它之后，电脑上的 GDB 客户瑞就能通过 TCP/IP 协议连上当前设备，并调试相关的进程。ip[6]tables通过命令行，管理内核中的 IPTable (防火墙和流量限制）keystore_cli命令行实用程序，用于与 keystore（密钥存储）服务交互logcat把系统日志打印到标准输出上去，它也支持一些过滤选项。ndc与网络管理（Network Management）守护进程交互的命令行程序perf异常强大的性能分析（profiling）工具，它使用了内核中支持性能分析的一些功能ping[6]封包网络探针（Packet Internet Grouper), ICMP 协议的 echo 请求/响应包radiooptions用来模拟无线接口层（Radio Interface Layer）事件的测试程序run-as能用指定的 AID 权限运行某个应用程序screencap把帧缓存（framebuffer）抓取到标准输出或一个 PNG 文件中（供 ADB 使用）screenrecord视频录屏工具，录制 .mp4 格式的视频screenshot与 screencap 功能一致service与 service manager 交互的命令行实用程序toolboxAndroid 提供多种命令的二进制可执行文件vdc与 vold (Volume 守护进程）交互的命令行实用程序wpa_cli与 wpa_supplicant 适配层交互的命令行实用程序/system/bin 调用 Dalvik 的脚本这些调用 Dalvik 的脚本让用户通过 shell 与 Dalvik运行时框架交互，这多半是为了进行调试 。这些脚本调用 /system/bin/app_process ，用它们在 /system/framework 目录中的同名 JAR 框架，加载 Dalvik 类，在使用时，脚本会把用户传给它的参数直接传递给 Dalvik 类。app_process 脚本功能解释am与 ActivityManager 进行交互、启动 activity 发起 intent 等bmgr备份管理（Backup Manager）接口bu启动备份content与 Android content provider 交互的接口ime控制输入法编辑器（ Input-Method-Editors)input与 InputManager 进行交互，注入输入事件media控制当前的媒体播放器（播放/暂停等）monkey用随机生成的输入时间运行一个 APKpm与包管理器（PackageManager）进行交互，可以用来列出、安装、删除包（ package ）以及列出权限等requestsync同步账号settings获取、设置系统设置svc控制电源、数据、Wi-Fi 和 USB 服务utautomator进行 UI 自动化测试，测试 dump view 之间的层次关系等wm与窗口管理器（WindowManager）进行交互、修改显示的尺寸/分辨率等/system/bin 厂商定制的二进制可执行文件（例如）这类二进制可执行文件可以完全由厂商控制，但是这类二进制可执行文件通常都是些提供服务的程序或调试工具。目录或文件功能解释mm-qcamera-daemon高通内置摄像头的守护进程mpdecisionMulti-Processor Decision：管理 CPU 主频的专用工具。它与 CPU governor 进行交互，能在系统忙时，加快主频或激活其他处理器（core），也能在系统空闲时，降低主频或让一部分处理器休眠qmuxd高通基带访问多路转接器（baseband access multiplexer)qseecomd高通安全执行环境通信器（Secure Execution Environment Communicator)thermal-engine-hhthermal 守护进程，负责监视设备的温度，防止设备过热/system/xbin 文件系统/system/xbin 目录类似于 UNIX 中的 /sbin 目录，其中含有管理员会觉得非常有用的二进制可执行文件。当然这个目录一般是被厂商删除的，一般 root 就是在这个目录放一个 su 文件。目录或文件功能解释su切换用户为（root 或者其他用户）add-property-tag向系统的 .prop 文件中添加属性check-lost+found在 fsck 操作完成之后，检查 lost+found 目录cpueater用于消耗 100% CPU 资源的死循环cpustats显示 CPU 和处理器调节然（用于控制主频）的统计信息/system/lib 文件系统/system/lib（在 64 位系统中则是 /system/lib64）目录中含有供 /system/bin 和 /systern/xbin 目录中的二进制可执行文件使用的共享库。/system/lib 中有多个子目录，其中的一些是根据设备的不同而不同的。目录或文件功能解释/drm提供 DRM 引擎。比如，实现了 forward-locking 专利代码包的 libfwdlockengine.so/eglAndroid 版的 OpenGLES/hw各个 HAL 模块/ssl/engines含有 libkeystore.so，该共享库使得 OpenSSL 能使用 Android 的 Keystore 机制/system/etc 文件系统就像它在 UNIX 系统中的同名目录一样， Android 的 /system/etc 目录中也存放着各种配置文件之类的东西。目录或文件功能解释NOTICE.html.gz无数个 Android 沂源组件的法律告知l书 ， 说明各种晦涩难懂的许可授权和法定事宜。audio_effects.conf会被 Android 的音频 HAL 使用audio_policy.conf会被 Android 的音频 HAL 使用apns-conf.xmlTelephony provider 的配置文件，其中列出了设备所支持的所有运营商（它会被 com.android.providers.telephony.TelephonyProvider 使用asound.conf设备 ALSA ( Advanced Linux Sound Architecture ）的配置文件，它会在某些设备上被使用bluetooth/BlueDroid 的配置文件clatd.confCLATd（实现 IPv4 over IPv6 ）的配置文件event-log-tags各个不同 Android 系统组件的日志 tag（被 android.util.EventLog 使用）fallback_fonts.xml列出了在加载 system_fonts.xml 中没有指定的 font-family 时所能选用的 fallback font。它会被 Android 中的 layoutlib 的 FontLoader 所使用gps.confGPS 配置文件hosts主机－IP 对应关系表，为了兼容起见，其中也记上了 localhost (127.0.0.1)media_codecs.xml列出了 Stage Fright 所支持的所有 codec（编码/译码器）media_profiles.xml列出了 LibMedia 所支持的所有 profileppp/存放了启动/停止 VPN 和 PPP 连接活动的二进制可执行文件permissions/存放了多个 XML 文件，每个 XML 文件规定了个内置应用（不论是 AOSP 的还是厂商提供的〕的权限，它会被 PackageManager 使用security/这个目录中含有存放着设备中硬编码写死的各个认证证书的目录（ cacerts/）。 OTA 升级的证书（otacerts.zip）以及经过签名验证的 APK 的 SELinux 标签（label）system_fonts.xml按照字体（font〕所属的 family 和 nameset，列出了系统字体（font），并把字体样式（font style) 和 /system/fonts 中的各个 TTF 文件一一对应起来，它会被 Android 中的 layoutlib 的 FontLoader 所使用wifi/WPA supplicant 适配层的配置目录，用于控制 Wi-Fi 和 Wi-Fi P2P 连接活动*acdb(高通芯片组) 各种声音校附数据库文件，在高通设备中会被 libacdbloader.so 使用snd_msm/(高通芯片组)存放高通 MSM Soc 音频设备的 ALSA 文件thermal*.conf(高通芯片组)监视设备温度的 thennald 守护进程的配置文件/data 文件系统/data 分区是所有用户个人数据的存放地点。目录或文件功能解释anrdumpstate 用来记录失去响应的 Android 应用的函数调用校当前状态的地方。app用户自己安装的应用，下载下来的 .apk 文件都可以在这里被找到app-asec存放 asec 容器， 当一个应用使用了 asec 保护技术时，它就会被加密起来app-lib应用（不论是系统应用还是用户自己安装的应用)的 JNI 库都可以在这里被找到app-private提供应用私有存储空间，已经很少使用backup供备份服务使用bugreportsbugreport 专用，用来存放生成的报告，每份报告中均含有一个文本文件和一张屏幕截图dalvik-cache用于存放优化过的系统应用手日用户安装的应用的 classes.dex 。每个应用的 dex 文件名都是它 apk 包的存放路径，并用“＠”替换掉了路径分隔符data各个己安装应用的数据目录drm供 Android 的数字版权管理器〔Digital Rights Management）使用local供 uid shell 使用的一个可读/可写的临时目录lost+found对 /data 分区执行 fsck 操作时自动生成的目录。media供 sdcard 服务把 SD 卡 mount 到这个 mount 点上mediadrm供 Media DRM 服务使用misc供各个组件存放“各式各样的”数据和配置文件的目录nfc存储 NFC 参数property存放持久性属性resource-cache供 AssetManager 使用的资源缓存secunty通常为空ssh供那些提供 ssh (Secure Shell）服务的设备使用system存放了大量系统配置文件tombstones用于存放由 debuggerd 生成的应用崩溃报告。user不同的用户会把各自的数据和应用存储/安装在 /data/user/用户号/（用户号从 0 开始顺序编号，0 ,1...）下的各个目录中，系统运行时，把 /data/data 下的对应目录做符号链接，使之指向 /data/user/用户号/ 下的对应目录，以这种方式让 Android 系统能支持“多用户”。在一个单用户系统中, /data/data 会被直接指向 /data/user/0/data/data 文件系统/data/data 目录是所有应用（不论是系统应用还是用户安装的应用〕存储它们的信息的地方。每个应用都可以访问属于自己的文件夹而不用申请权限，其他的应用都有权限列出 /data/data 的子目录，但是不能访问。/data/misc 文件系统/data/misc 目录中含有各个 Android 子系统的各种五花八门的（miscellaneous）数据和配置目录。目录或文件功能解释adb存储可信的允许进行 ADB 连接的电脑的公钥bluetoothBlueZ [<4.2 的 bluetooth（蓝牙〕子系统的配置文件bluedroidBluetooth（蓝牙）子系统（>4.2）的配置文件dhcp存储实现 dhcp 的 ctdent 守护进程的 PID 文件，以及所有当前活跃的地址租用记录keychain存放 Android 内置证书 pin 码（certificate pin）和黑名单keystore存储每个用户的 keystore 数据sensors用于存储传感器调试数据sms存储短信(sms) codes 数据库systemkeys用来存储打开 ASEC 容器的密钥（AppsOnSD.sks)vpn用于存储 VPN 状态自己置文件wifi用于存储 Wi-Fi 子系统的配置文件（比如：wpa_supptdcant.conf）和套接字（socket)/data/system 文件系统/data/system 目录中含有对维护设备状态非常重要的文件。访问该目录需要 root 权限。目录或文件功能解释appops.xml供控制应用权限的 AppOps 服务使用batterystats.bin供统计各个应用电量使用情况的 BatteryStats 服务使用called_pre_boots.dat供 ActivityManager 记录每个 boot broadcast receiverdevice_policies.xmlDevicePolicyManagerService 使用的配置文件dropbox/供 DropBox 服务使用的目录entropy.dat系统熵存储器（system entropy store），供 EntropyMixer 生成随机数使用，随机数生成在一个计算机系统中是个难题，必须要有一个不能重复的熵，所以使用系统运行的各种操作记录、硬件运行记录来作为随机数的熵。gesture.key锁屏图案的 Hashframework_atlas.config供负责将预加载的 bitmap 组装成纹理贴图的 AssetAtlasService 使用ifw/Intent 防火墙规则库locksettings.db*锁屏设置：其中记录了设备的锁屏策略netpolicy.xml供 NetworkPolicyManagerService 使用的配置文件netstats/用来记录 NetworkStatsService 按 device、uid 或 xt 得到的网络传输数据统计的目录。packages.listPackageManager 列出的所有安装在系统中的包（APK)packages.xmlPackageManager 在此记录了所有己安装包的元数据password.key锁屏 PIN 码/口令的 hashprocstats/供 ProcessStats 服务存储文件的目录registered_services/供 android.content.pm.RegisteredServicesCache 使用的目录usagestats/供 UsageStats 服务存储文件，特别是 usage-history.xml 文件的目录users/Android 的“多用户”支持/cache 文件系统Android 是在系统升级的过程中使用 /cache 分区的。系统升级包会被下载到这里，启动管理器（boot manager）特别是在 recovery/ 升级模式下启动时，会要使用这个分区。但除此之外，在正常情况下，这个分区是空的。宏定义目录或文件功能解释CACHE_LOG_DIR/recovery二进制可执行文件 recovery 的专用目录LAST_LOG_FILE/recovery/last_log上一次 recovery/ 到级操作的日志LOG_FILE/recovery/log当前 recovery/ 升级操作的日志COMMAND_FILE/recovery/command传递给 recovery 的命令行参数INTENT_FILE/recovery/intentrecovery 完成之后要发出 的 intentLAST_INSTALL_FILE/recovery/last_install最近一次安装日志LAST_LOCALE_FILE/recovery/last_locale存放再次启动时使用的语言设置/vendor 目录目录是用来存储厂商对 Android 系统的修改的。组件名目录或文件Package Manager/vendor/appFonts/vendor/etc/fallback_fonts.xmlShared Libraries/vendor/libDRM libraries/vendor/lib/drm /vendor/lib/mediadrmeGL libraries/vendor/lib/eglFrameworks/vendor/overlay/frameworkFirmware/vendor/finnwareAudio Effects/vendor/etc/audio_effects.conf/dev/usb-ffs/adb 目录 functionfs在 Android 系统中，USB 的功能经常会需要根据用户的选择（即 ， 是以 USB 调试、大容量存储介质还是 以其他方式连接设备，用户的这一选择将通过 init 传递进来）动态地进行重新配置，它是由一个特定的 “gadget” 驱动进行控制的 。/proc 目录procfs 文件系统名副其实一一它提供了一个基于目录的观察系统中运行的进程的方式。使之能提供大量关于进程、线程以及其他全方位的系统诊断信息。许多 Linux 实用程序（如 top、netstat、lsof 和 ifconfig）以及许多 Android 工具（如 procrank、librank）都把它作为诊断信息的来源，没有它就不能运行 。/sys 目录sysfs 是在 Linux 内核版本 2.6 中作为对 procfs 的补充而被引入的，为了能把 /proc 里的东西整理得井井有条些，把与硬件和模块相关的配置文件移到一个单独的目录中去，并让目录的层次也更清晰些 。目录作用block存放块 I/O 层 (Block I/O Layer）的控制文件。每个块设备都有自己的子目录，其中记录了其所属的 I/O 调度程序等参数bus设备，按连接它的总线类型分类存放，每种总线类型（比如 i2c/、mmcl、soc/）一个子目录class设备，按设备类型分类存放，每种设备类型（比如 input/、sound/）一个子目录dev设备，按设备读写方式分类存放，每种读写方式（比如 block/、char/） 一个子目录devices设备，按设备在设备树（device-tree）上的分类类型存放frimware供有固件升级功能的设备使用fs供文件系统驱动使用。kernel由各个（内核）子系统提供的一些内核参数，其中的 debug/是 debugfs 的 mount 点module每个极块一个子目录，含有极块的统计信息以及模块参数power电源管理（power management）的统计信息和设置，Android 的 WakeLocks 就是在这里（通过 wake_lock 和 wake_unlock 〕实现的/sys/kernel/debug 目录 debugfsdebugfs 文件系统是用于（输出）内核级的调试信息的。驱动以及类似的子系统可以自由地把驱动的调试信息转储到这个文件系统中。目录作用binder提供通过 Android IPC （进程间通信）机制中的 binder 方式传递的大量数据tracing好用到难以置信，提供由 Linux 内核的 flrace 机制产生的海量的调试和跟踪信息wakeup-sources内核级的定时器，用在 Android 系统或驱动程序防止设备休眠时/sys/fs/pstore 目录 pstorepstore 机制是 Linux 的一个内核特性（在 3.5 版时引入），它允许内核把部分物理内存(RAM)单独划为 persistent store 区 。 它对于一种特定的应用抓取内核崩愤（panic）时的数据，非常有用。/sys/fs/selinux 目录 selinuxfs和 debugfs 一样，SELinuxFS 传统上也是 mount 在 /sys 下，但却不是 sysfs 文件系统的一部分。这个文件系统是专供 SELinux 使用的，其中存储了与安装策略（installed policy）相关的文件。参考资料部分来源于网络 XDA 论坛部分来源于《最强 Android 书：架构大剖析》
我没有 Root 的手机，我又想看相关目录怎么办
标签: Android 开发小技巧如题目，我没有拥有 Root 权限的 Android 手机，我又想看 Android 系统的相关目录怎么办？今天我们用 Android Studio 自带的虚拟机来解决一下这个问题。因为 Windows，Mac 等等的可能快捷键不一样或者因为 Android Studio 版本的问题按钮位置或图标不一样。知道怎么能够快捷打开就不用看我啰嗦了。所以下文讲的操作方式无论在哪个版本和平台上都一样的。本文将介绍，如何拥有一个 Root 的系统环境，以为学习 Android 系统、App 调优等等需求做铺垫。创建虚拟机管理器在 Android Studio 页面按两下 Shift 键，输入 avd manager ，如果有多个选项，注意是选 Actions 这一栏下面的 AVD Manager，打开虚拟机管理器。然后创建一个新的虚拟机。然后外观你可以随便选，然后点击 Next。这一步很关键了，我们不要使用推荐的镜像，首先将选项卡切到 X86 镜像。这里我们要选择的是右边名称中没有（Google APIs）字样的系统镜像，如果不能选就需要点击左边 Download 先下载。下载完成镜像后选择下载的镜像，直接点击 Next。同样这一步如果没有特殊需求不建议做修改，直接点击 Finish 完成。这样我们的虚拟机就创建完毕了。如果想打开虚拟机，直接在虚拟机管理点三角打开即可。查看虚拟机文件你可能会因为操作系统版本或 Android Studio 版本问题找不到这个功能，所以以下展示通用开启方式，如果你知道怎么打开直接打开就可以。前提是你先打开了虚拟机。同样我们按两下 Shift 键，输入 device file explorer ,如果有多个选项，注意是选 Actions 这一栏下面前面带图标的 Device File Explorer ，打开该功能。如图，每个文件夹都有不同的功能和作用，具体详情请看我的博客 Android 系统目录功能速查。ADB 带 Root 权限的调试如果自己配置过 ADB 环境，你想使用系统的终端或 CMD 命令窗都是可以的，这里使用通用方案。在 Android Studio 页面按两下 Shift 键，输入 terminal ，如果有多个选项，注意是选 Actions 这一栏下面前面带图标的的 Terminal，打开 Android Studio 的终端。如果你是第一次打开并使用你新创建的虚拟机，那么你先要输入一句 adb root 命令，来开启 ADB 的 Root 权限。然后输入 adb shell 就可以进入手机调试了。如何区分你进入的 ADB shell 是不是 Root 权限，你先输入 adb shell 命令打开调试，你看终端显示的符号，如果是 $ 就不是 Root 环境，如果显示 # 就是 Root 环境了。接下来你就能够使用带 Root 权限的 ADB 命令了。比如我们可以进入 /proc 文件夹看各项服务的进程状况。更多 ADB 用法 ADB 用法大全
这是一篇极短的技巧文，但是能解决你使用 ConstraintLayout 布局最大的痛点废话不多说直接上配置：打开 Android Studio 设置 Editor -> General -> Code Completion 选项卡，然后如图设置。然后你会获得什么能力呢？来个 Gif 看看，千万要忍住惊讶！前方高能预警！高能预警！简单解释下我们调节的这个选项是干什么的，他是调整代码提示规则的这个选项有三个选项分别是 All、None、First letterAll代码提示规则是不区分大小写的，但是对单词顺序有要求，也就是拼写完全正确的才能提示出来None代码提示规则是不区分大小写的，但是对单词顺序也没有要求，也就是拼写能够模糊搜索到方法名或类名或变量名的就提示出来First letter代码提示规则是区分大小写，并且是对单词顺序有要求，也就是拼写完全正确（包括大小写）的才能提示出来总结看清楚没有各位观众老爷，各种喜欢啊，赞赏啊向我投过来，砸死我吧！
这篇文章呢我们谈一谈，约束布局常用的一些需求和坑一、如果我想让一个控件在父布局里左右填充怎么办（上下填充，上下左右都填充同理）match_parent 方式<View android:id="@+id/a" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/holo_red_light" />相对布局的方式（android:layout_width="0dp" 是关键）<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" />ConstraintLayout 没有 match_parent 所以推荐使用第二种方式，虽然看效果是没啥事，但是官方的坑我表示不踩二、替代百分比布局有时候想把控件按照比例填充父布局，Android 屏幕适配这么复杂，好像不容易实现这时候约束布局有两个属性 layout_constraintWidth_percent layout_constraintHeight_percent这岂不是把一直不温不火的百分比布局给革命了<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintWidth_percent="0.3" />我只放这么一段代码大家应该就知道怎么用了，我也就不多了说了。默认是居中的如果想调整位置请结合 app:layout_constraintHorizontal_bias="0.3" 食用三、控件宽度一定，我想左右居中显示怎么办（上下居中同理）<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" />与左右填充相似，只不过宽度固定了而已，两条绳子拉着一个控件居中四、控件宽度一定，左右按百分比显示怎么办，我就是不想居中（上下同理）<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintHorizontal_bias="0.3" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> app:layout_constraintHorizontal_bias="0.3" 一个属性就搞定了上下使用 app:layout_constraintVertical_bias 来实现五、我想两个控件左右平分空间，对没错就是抢 LinearLayout 的饭碗（上下居中同理）<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_blue_light" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toRightOf="parent" />因为有个约束链的存在所以这个稍微有点复杂，先来一张约束示意图看一下，约束链下边在讲六、我想两个控件左右按比例平分空间，平分多没有意思啊（上下同理）<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_blue_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toRightOf="parent" />上面的例子是 1：2 看写法是不是和 LinearLayout 的权重写法简直一毛一样上下权重设置 app:layout_constraintVertical_weight="" 一定记得 android:layout_width="0dp" 是 0dp坑点宽高在需要自动控制长度的时候一定是设置为 0dp，不然没什么效果，甚至达不到预期，我也推荐约束布局中只是用 0dp 、wrap_content 、固定的值。切记 match_parent 是没啥卵用，虽然看着有效果，但是我也不敢碰，说多了都是泪。切记只有约束过的边设置 margin 才能看出效果，注意我说的是能看出，虽然设置了 margin 也是有意义的但是看不出来平时我们摞控件的时候一定记得处理右边和底部的约束，好多人控件显示不全就是这个问题
谷歌之前推出了 ConstraintLayout 动画，做一些基本的动画让我们更省时省力了，今天我们就看一下这个小知识点。首先你需要引入 constraint-layout 这就不用我多说了然后还需要引入 transition 包，如果不引入，从而使用系统自带的 transition 的话，则你的约束布局动画只能兼容到 API 19implementation 'com.android.support.constraint:constraint-layout:1.1.2' implementation 'com.android.support:transition:27.1.1'我们先说一说最简单的实现方式，使用两个布局，第一个是我们正常的布局，另一个是记录控件变换后位置与约束信息的布局首先贴上正常的布局<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/root_layout" tools:context=".MainActivity"> <View android:id="@+id/a" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_red_light" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="60dp" android:background="@android:color/holo_blue_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>预览下原始布局然后贴上标定位置的布局<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <View android:id="@+id/a" android:layout_width="0dp" android:layout_height="60dp" android:layout_margin="20dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="60dp" android:layout_margin="20dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/a" /> </android.support.constraint.ConstraintLayout>大家发现了没有这个布局颜色，按钮文字什么属性我都没有写，因为不需要，这个布局只提供一个控件的位置与约束信息，做动画就是从默认布局到这个布局的一个渐变我放的图片有颜色是我故意加的，为了能让大家直观的看到两个控件的位置，代码中其实是并不需要的再看一下 Activity 的写法 private ConstraintSet mConstraintSet1, mConstraintSet2, mConstraintReset; private ConstraintLayout constraintLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mConstraintSet1 = new ConstraintSet(); mConstraintSet2 = new ConstraintSet(); constraintLayout = findViewById(R.id.root_layout); //把默认 constraintLayout 布局放到 mConstraintSet1 中 mConstraintSet1.clone(constraintLayout); //把标定位置变换的 constraintLayout 布局放到 mConstraintSet2 中 mConstraintSet2.clone(this, R.layout.activity_main_anim); } public void onClick(View view) { switch (view.getId()) { case R.id.btn_start: TransitionManager.beginDelayedTransition(constraintLayout); mConstraintSet2.applyTo(constraintLayout); break; case R.id.btn_reset: AutoTransition transition = new AutoTransition(); transition.setDuration(500); TransitionManager.beginDelayedTransition(constraintLayout,transition); mConstraintSet1.applyTo(constraintLayout); break; } }首先动画效果看了，看了一眼代码是不是觉得这种写法代码冗余很严重有木有，这个动画不止有这一种写法，先不要放弃他，我们就来逼叨逼叨！首先我们有两个布局，第一个是正常的布局，包括文字颜色什么的都有，第二个布局只有与约束相关的代码和相关控件以及 ID。我们第二个布局就算你写了其他的属性系统再做动画的时候他也不会读，所以就是没什么卵用。看到这里大家心里肯定有一个疑问，我们平常设置 View 的字体、文字、颜色、背景什么的会不会出现什么问题，我这里试过了，什么问题都没有，包括 View 的 ID 只要我们默认布局有就不会有问题。再说一点本来应该和第一点写一起的但是我觉得这一点很重要：我们第一个布局里面各个控件以及 ID 在第二个布局一定要保持不变，切记 ID 不要变，因为变了系统去做动画的时候就达不到预期效果了，举个例子：本来我们有两个控件 ID 分别为 A,B ，但是我们在第二个布局改成了 B,C 那么做动画 A 就会因为没有约束而乱做动画，只有 B 做动画效果想做动画必须用 ConstraintLayout ，并且子布局里面的控件是不会做动画的用法简述有几种动画状态就需要创建几个 ConstraintSet 因为约束布局的动画都依赖于 ConstraintSetConstraintSet.clone(); 使用这个方法把布局位置以及约束关系记录到 ConstraintSet 中。该方法有以下几种构造方法自己按需求选择public void clone(Context context, int constraintLayoutId)public void clone(ConstraintSet set)public void clone(ConstraintLayout constraintLayout)public void clone(Constraints constraints)我们上面说的如果不想再画一个布局那就是用代码自己编辑约束关系，例如：mConstraintSet2.clone(constraintLayout); mConstraintSet2.centerVertically(R.id.a, 0)ConstraintSet 里面的 API 可以自己看一下，基本就是 ConstraintLayout 里面的那些属性，如果懒得话，乖乖再画一遍布局吧TransitionManager.beginDelayedTransition(constraintLayout) 准备开始动画我们还可以自定义动画时长等等操作，具体 AutoTransition API ，例子：AutoTransition transition = new AutoTransition(); transition.setDuration(500); TransitionManager.beginDelayedTransition(constraintLayout,transition);mConstraintSet1.applyTo(constraintLayout); 然后把 ConstraintSet 位置和约束信息应用到 ConstraintLayout 布局，并且做动画如果手动修改了 ConstraintLayout 中元素的布局位置，那么动画不会同步这个变化，因为他们的位置等信息都存在 ConstraintSet 中，你就算改了 ConstraintLayout 中元素位置也没什么用，除非你自己改了，记得要重新记录到 ConstraintSet 中。小结虽然这个知识点很小，但是用好了能给我们的 APP 添加很多逼格，学习这个知识点的收益真的是很划算
我之前写过一篇 ConstraintLayout 的文章现在已经到了 2018 年，最新正式版本也已经到了 1.1.2 ，又加了不少好用的特性，可以说这个约束布局已经成为 Android 中最强大的布局了，绝对不是吹嘘。本篇文章只会讲怎么使用代码画布局，可视化的方式精准度方面还是有点差强人意，如果你想了解可视化方式，请看我之前的文章。让我们看一看这个 Android 中最强大的布局吧！相对定位一、基本用法相对定位约束布局最基本也最常用的使用方式我们先简单看一下用法<TextView android:id="@+id/a" android:layout_width="60dp" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="20dp" android:gravity="center" android:layout_marginTop="30dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" android:text="A"/> <TextView android:id="@+id/b" app:layout_constraintTop_toTopOf="@+id/a" app:layout_constraintLeft_toRightOf="@+id/a" android:layout_width="60dp" android:layout_height="wrap_content" android:gravity="center" android:text="B" />我们先看 A 控件，A 的位置怎么来的呢？app:layout_constraintTop_toTopOf="parent" A 的顶边与 parent 的顶边对齐app:layout_constraintLeft_toLeftOf="parent" A 的左边与 parent 的左边对齐我们看到 A 与左边上边都有一个空隙， 这就是普通的 android:layout_marginXXXX 属性，我也就不细说了我们再看 B 控件，B 的位置怎么来的呢？app:layout_constraintTop_toTopOf="@+id/a" B 的顶部与 A 的顶部对齐app:layout_constraintLeft_toRightOf="@+id/a" B 的左边与 A 的右边对齐B 控件我没有设置 margin 所以他们是贴在一块的从上面的例子我们看到了两个问题看到两个控件 app:layout_constraintXXX_toXXXOf="xxx" 属性的值不一样，一个写的是控件 ID，一个是 parent ，这是什么意思呢？一般控件去约束需要一个参照物，这个参照物标识可以是控件的 ID ，也可以是父布局（父容器) —— parent就好比一根绳子一端拴在当前控件的某一位置，另一端拴在参照物的某一个位置上，这就建立起了约束。如果仔细看上述代码，大家肯定还有一个疑问，我明明在 A 控件上设置了 marginRight 为什么 A 和 B 还是贴着的，这就有一个说法，如果一个边没有约束那么他对应边的 margin 是不生效的OK 理解起来很简单不是吗，约束布局最基本的语法就是 app:layout_constraint位置_to位置Of="看齐目标" 那么像这种普通的相对定位的写法有多少种呢，我来给你们列举一下，再配张图标出它们的具体位置，看完下面基本的约束布局用法你就已经了解了。layout_constraintLeft_toLeftOf layout_constraintLeft_toRightOf layout_constraintRight_toLeftOf layout_constraintRight_toRightOf layout_constraintTop_toTopOf layout_constraintTop_toBottomOf layout_constraintBottom_toTopOf layout_constraintBottom_toBottomOf layout_constraintBaseline_toBaselineOf layout_constraintStart_toEndOf layout_constraintStart_toStartOf layout_constraintEnd_toStartOf layout_constraintEnd_toEndOf当然有一部分控件没有 Baseline 这个位置，所以这个位置不是对每种控件都有效的二、圆形定位<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/b" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintCircle="@id/a" app:layout_constraintCircleAngle="45" app:layout_constraintCircleRadius="100dp" />偷偷放一张图片app:layout_constraintCircle 需要看齐的参照物，图中 B 就是把 A 当做参照物进行约束的 app:layout_constraintCircleAngle 要旋转的角度，最上方 0 度，默认就是 0 度，顺时针开始算。app:layout_constraintCircleRadius 两个控件中心点的距离约束链能够在水平或垂直方向控件之间相互约束而组成的一条链就是约束链，约束链是由开头的控件进行属性控制的。没错就是跟着大哥走普通的约束链示例<View android:id="@+id/a" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" app:layout_constraintTop_toTopOf="parent" /> <View android:id="@+id/b" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toLeftOf="@+id/c" app:layout_constraintTop_toTopOf="@+id/a" /> <View android:id="@+id/c" android:layout_width="80dp" android:layout_height="50dp" android:background="@android:color/holo_green_light" app:layout_constraintLeft_toRightOf="@+id/b" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="@+id/a" />看到 A 控件就是引领小弟们的链头，所以众小弟都听他的。我们看到它的 app:layout_constraintHorizontal_chainStyle="packed" 属性。这个属性有三种值packed：控件紧挨在一起。还可以通过bias属性设置偏移量。spread：均与分布控件。spread_inside：均与分布控件，但是两边控件贴边。我贴几张图大概看一下样子当然如果是垂直的就是 app:layout_constraintVertical_chainStyle="xxxx" 属性组合 layout_constraintHorizontal_bias 的约束链如果链的样式是 packed 我们还能组合 layout_constraintHorizontal_bias 使用，我就不贴代码了，直接上图了解下还有一种特殊的约束链，就是按照控件权重平分控件（明摆着抢 LinearLayout 饭碗）<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintHorizontal_weight="1" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toLeftOf="@+id/b" /> <View android:id="@+id/b" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_blue_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toLeftOf="@+id/c" /> <View android:id="@+id/c" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_green_light" app:layout_constraintHorizontal_weight="2" app:layout_constraintLeft_toRightOf="@+id/b" app:layout_constraintRight_toRightOf="parent" />这种链就是不设置链的 style 而是用权重的方式进行排布。约束布局散乱特性一、动态推测控件的宽或高我们约束布局还支持这样的一种情况，我们控件只确定了控件的宽、高的其中一个，然后按比例算出另一边的宽高。（当然这个需求很小众） app:layout_constraintDimensionRatio="2:1" 这个属性就是按比例推测宽高的属性<View android:id="@+id/a" android:layout_width="100dp" android:layout_height="0dp" android:background="@android:color/holo_red_light" app:layout_constraintDimensionRatio="2:1" app:layout_constraintLeft_toLeftOf="parent" />看以上代码 2:1 其实就是 width/height = 2/1 ，height = 50dp，所以这个属性的就是 width/height ，由此我们只要给定宽或高就能推出另一个。（当然如果你宽高都确定了设置这个属性就无效了）这个属性的值还能设置为 (H,2:1)，(W,2:1) 这样的，其实我看到之后是一脸懵逼的，但是还要硬着头皮研究，H 就是 Height，W 就是 Width，好吧说一下规律。(H,2:1)如果确定宽宽：高度 = 100 * 1 / 2如果确定高度：宽度 = 100 * 1 / 2(W,2:1)如果确定宽宽：高度 = 100 * 2 / 1如果确定高度：宽度 = 100 * 2 / 1虽然我这样说了但是还是不推荐用。本来就是小众功能如果想用还是用普通的写法就行了，不要带什么 H，W 了。装逼太刺眼！二、父布局填充约束有时候有这么一个需求想把控件按照比例填充父布局。Android 屏幕适配这么复杂，好像不容易实现这时候约束布局有两个属性 layout_constraintWidth_percent layout_constraintHeight_percent怎么看怎么像百分比布局，这岂不是把一直不温不火的百分比布局给革命了<View android:id="@+id/a" android:layout_width="0dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintWidth_percent="0.3" />我只放这么一段代码大家应该就知道怎么用了，我也就不多了说了。默认是居中的如果想调整位置请结合 app:layout_constraintHorizontal_bias="0.3" 食用三、聊一聊 margin 属性有人要说了 margin 属性还用你说？当然了我并不会说，我要说的是 layout_goneMarginStart 没见过吧？这个是什么意思呢，如果要约束控件隐藏了，B 控件位置还想保持不动怎么办呢，那么这是个什么情况呢？举个例子 B 控件左边相对 A 控件进行定位，并设置了 20dp 的 marginLeft。如果把 A 隐藏了会怎么样呢？分别看一下图1、图2。给我们的 B 控件加上两个属性app:layout_goneMarginLeft="100dp" app:layout_goneMarginTop="30dp"预想的效果很棒，不是吗，从此我们看出 goneMarginXXXX 就是在约束的目标控件隐藏时才会生效的 margin。四、WRAP_CONTENT 的小问题如果你的控件宽或高是 wrap_content 并且控件长度过长时，他的约束会失效，我们看个例子<View android:id="@+id/a" android:layout_width="120dp" android:layout_height="50dp" android:background="@android:color/holo_red_light" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/b" android:layout_width="wrap_content" android:layout_height="50dp" android:background="@android:color/holo_blue_light" android:text="是事实是事实是事实是事实是事实" app:layout_constraintLeft_toRightOf="@+id/a" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/a" />解决方式就是使用app:layout_constrainedWidth="true" app:layout_constrainedHeight="true"五、最小高度宽度，最大高度宽度设置最小尺寸layout_constraintWidth_min and layout_constraintHeight_min设置最大尺寸layout_constraintWidth_max and layout_constraintHeight_max没啥好说的。六、控件位置偏移app:layout_constraintHorizontal_bias="0.3" app:layout_constraintVertical_bias="0.3" 相信这两个属性在上面大家都看过好多遍了吧，如果控件没有占满父布局，它是可以控制当前控件在父布局的空间里所占的位置，放张图理解一下。就跟拔河一样哈哈该属性的取值范围是 0 - 1这是横向的分析，竖向与这个一致约束布局辅助工具一、 辅助定位线Guideline 是一个帮助我们来定位控件，但是他又不被用户所感知。<android.support.constraint.Guideline android:id="@+id/line" android:layout_width="wrap_content" android:orientation="vertical" android:layout_height="wrap_content"/>上面的最基本的写法id 是必须的不然怎么约束android:orientation="vertical" 来控制横向还是竖向，用过线性布局应该都知道这个属性他核心的三个属性layout_constraintGuide_begin="100dp" 距离父容器起始位置的距离layout_constraintGuide_end="100dp" 距离父容器结束位置的距离layout_constraintGuide_percent="0.3" 距离父容器宽度或高度的百分比，取值范围 0 - 1如果上述三种属性同时出现，优先级由高到低 layout_constraintGuide_percent > layout_constraintGuide_begin > layout_constraintGuide_end二、 控件组Group 可以同时控制多个控件的显示与隐藏<android.support.constraint.Group android:id="@+id/group" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="visible" app:constraint_referenced_ids="a,b" />android:visibility="visible" 控制显示隐藏，也可以在代码中根据 id 获取 Group 来控制显示隐藏app:constraint_referenced_ids="a,b" 受这个 Group 管理的控件们的 id，, 号隔开三、 控件屏障Barrier<android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="start" app:constraint_referenced_ids="button1,button2" />app:barrierDirection=“start” 属性可以控制这个屏障在哪个位置，具体位置可以参考文章开头那张介绍位置的图app:constraint_referenced_ids 屏障里面的控件们的 id，, 号隔开下面分析一个例子<TextView android:id="@+id/tv_name" android:layout_width="0dp" android:layout_height="wrap_content" android:text="姓名：sdfsdfsdsdf" app:layout_constraintBottom_toBottomOf="@+id/et_name" app:layout_constraintTop_toTopOf="@+id/et_name"/> <TextView android:id="@+id/tv_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="手机号：" app:layout_constraintBottom_toBottomOf="@+id/et_phone" app:layout_constraintTop_toTopOf="@+id/et_phone"/> <EditText android:id="@+id/et_name" android:layout_width="0dp" android:layout_height="wrap_content" android:hint="请输入姓名" app:layout_constraintLeft_toLeftOf="@+id/barrier" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <EditText android:id="@+id/et_phone" android:layout_width="0dp" android:layout_height="wrap_content" android:hint="请输入手机号" app:layout_constraintLeft_toLeftOf="@+id/barrier" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/et_name"/> <android.support.constraint.Barrier android:id="@+id/barrier" android:layout_width="wrap_content" android:layout_height="wrap_content" app:barrierDirection="right" app:constraint_referenced_ids="tv_name,tv_phone"/>放一张效果图首先把 et_name et_phone 位置放好，然后再把 tv_name tv_phone 放在屏障里，把他们当成一个整体然后 et_name et_phone 左边约束我们的屏障为什么 et_name et_phone 对齐的会是屏障的右边，因为 app:barrierDirection="right" 这个属性控制的，如果改成 left 就会变成如下的样子，全都和屏障的左边去对齐了这个屏障有点稍微复杂那么一丢丢，大家多多实践一下小结OK 我在这里写了约束布局的一些用法，那么下一篇我将会继续絮叨絮叨这个约束布局在我们平常开发常用的一些写法和技巧！如果还有些看不懂，请配合官方文档食用，毕竟官方资料才是我们的一手资料参考资料官方文档
我们先讲个小故事理解一下。盛唐年间，天下安定，由于疆域太大传递信件不易，就有民间的能人异士向皇帝谏言，每个州县都建立信息司来养信鸽。由信鸽来传递信件。皇帝觉得可行遍开始施行。一日皇帝命小吏从东都洛阳发一封信件到西京，这个小吏第一次去信息司发信件，到了信息司发现只有一个人处理信件。小吏便把信件交给了信息司的小哥，只见小哥娴熟的拿出只信鸽告诉它去西京，就放飞了，然后将信件誊抄了一份，将信件撕成了三份，并标上了序号。过了不一会小哥刚刚放走信鸽飞回来了，只见小哥又将信鸽放飞了。然后拿出三个信鸽分别将三份信件绑到信鸽的腿上，然后将信鸽放飞了。这时候小吏就问了小哥一句：”为什么刚刚只把信鸽放飞而不放信件啊！“。这时小哥不耐烦地说：”我要试试，我们州县附近有没有猎人，看看信鸽能不能飞出去。如果飞不出去就要找县衙派兵沿途检查一下路线了。“；小吏又问：”既然我们已经看到信鸽飞回来了，为什么还要再次放出去。“。小哥继续说：”西京那边还不知道他能不能发信鸽。我需要告诉他一声。“，谈话间只看到传递 1，3 号信件的鸽子飞回来了。小哥说：”又有一只鸽子飞丢了。“，小吏急忙问道：”怎么办！如果出了差错，我可是要被杀头的。“。小哥说：”莫着急我们再等一柱香的时间，如果还不回来我们在把 2 号信件重新发一次就好了。“。一炷香过后，小哥又拿出一只信鸽把 2 号信件绑到鸽子的腿上。不一会传递 2 号信件的信鸽飞回来了。只见小哥又娴熟的拿出一只信鸽放了出去，不一会飞回两只，然后小哥又放出去一只信鸽。小吏不解的问小哥：”你这个在干什么！“。小哥说：“我这是再告诉西京那边我的信息发完了。然后西京告诉我他知道了并让我把备份的信件销毁。我再告诉西京没问题”。终于皇帝的信件发完了。小吏回去后感觉比较有意思，东都西京中间隔着两个州，信鸽是怎么如何飞的呢？他又专程去问了信息司的小哥。小哥说：”我也不知道信鸽会飞到那个州，如果信鸽飞到其他州，其他州的人会看到信鸽的目的地是西京，他会改变信鸽的飞行方向，直到信鸽飞到西京才算结束。“。以上的小故事就是个简单 TCP 传输。小吏便算是应用层，皇帝让他去发消息。信息司的小哥身兼传输层和网络层。信鸽便是链路层。TCP/IP 分层网络1. 应用层应用层决定了向用户提供应用服务时通信的活动。TCP/IP 协议族内预存了各类通用的应用服务。例如：HTTP、SSH、FTP 等。2. 传输层应用层的下一层就是传输层，提供处于网络连接中的两台计算机之间的数据传输常见的传输层协议有 TCP、UDP 等。3. 网络层网络层又称网络互连层。网络层用来处理在网络上流动的数据包，数据包是网络传输的最小数据单位。该层规定了通过怎样的路径到达对方的计算机，并把数据包传送给对方。网络层的作用就是在众多选项内选择一条合适的传输路径。4. 链路层链路层又称数据链路层，网络接口层用来处理连接网络的硬件部分，控制操作系统、硬件的设备驱动。我们能够看到的交换机、网线、光纤等也属于物理层TCP 是什么TCP 的全称是传输控制协议（Transmission Control Protocol）位于传输层，它是一种有连接的协议，提供可靠的字节流服务[注1]。而可靠的传输服务是指，能够将数据准确可靠的传递给对方。数据为何能准确无误的送达目标处，就是因为 TCP 协议采用了三次握手策略，当然除了三次握手，TCP 协议还有其他手段来保证通信的可靠性TCP 三次握手发送端首先发送一个带 SYN 标志的数据包给对方接收端收到标有 SYN 的数据包后回传一个带有 SYN/ACK 标志的数据包表示确认信息发送端在发送一个带有 ACK 标志的数据包给接收端表示握手成功如果握手成功后连接断开，再次连接还需要重新握手TCP 四次挥手由于TCP连接时全双工的，因此，每个方向都必须要单独进行关闭，这一原则是当一方完成数据发送任务后，发送一个FIN来终止这一方向的连接，收到一个FIN只是意味着这一方向上没有数据流动了，即不会再收到数据了，但是在这个TCP连接上仍然能够发送数据，直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭，而另一方则执行被动关闭。第一次挥手：Client发送一个FIN，用来关闭Client到Server的数据传送，Client进入FIN_WAIT_1状态。第二次挥手：Server收到FIN后，发送一个ACK给Client，确认序号为收到序号+1（与SYN相同，一个FIN占用一个序号），Server进入CLOSE_WAIT状态。第三次挥手：Server发送一个FIN，用来关闭Server到Client的数据传送，Server进入LAST_ACK状态。第四次挥手：Client收到FIN后，Client进入TIME_WAIT状态，接着发送一个ACK给Server，确认序号为收到序号+1，Server进入CLOSED状态，完成四次挥手。UDP 是什么UDP 的全称是用户数据报协议（User Datagram Protocol）同样位于传输层，它是一种无连接的协议，提供面向事务的简单不可靠信息传送服务TCP 与 UDP 的差异TCP 是有连接的而 UDP 是无连接的TCP 是可靠的连接而 UDP 是不可靠的UDP 不需要各种可靠性策略所以相比 TCP 性能要高不少因为 UDP 的连接步骤少，报头内容少所以相比 TCP 更加的省流量TCP 只能一对一连接传递消息而 UDP 可以一对一、一对多、多对一和多对多参考参考资料 https://blog.csdn.net/huangxy10/article/details/8012180抓包软件 Wireshark注1：字节流服务是指，为了方便传输，将大块数据分割成报文段为单位的数据包进行管理的服务
文章目录Android 中有哪几种 ClassLoader？他们的作用和区别是什么？简述 ClassLoader 的双亲委托模型简述双亲委托模型在热修复领域的应用首先了解下 ClassLoader 是什么众所周知我们编写的 Java 程序编写的是 .java 文件，但是在运行运行前会将代码编译成 .class 文件，以 Android Studio 项目为例在一般在项目目录下的 /build/intermediates/classes/debug 文件夹中有很多小文件夹，点进去看这些都是 .class 文件，程序在运行时就是加载这些 .class 文件，那么负责加载这些 .class 文件的就是我们的 ClassLoaer。一般在 Android 中程序打包会把多个 .class 文件打包成一个或多个 .dex 文件1. Android 中有哪几种 ClassLoader？它们的作用和区别是什么？我们先看一下Android源码有几个 ClassLoader 我们发现 ClassLoader 是个抽象类并且有两个子类 SecureClassLoader 、BaseDexClassLoaderSecureClassLoader 的子类是 URLClassLoader ，其只能用来加载 jar 文件，然而 jar 文件在 Android 的 Dalvik/ART 上没法使用的。BaseDexClassLoader 的子类是 PathClassLoader 、DexClassLoader 和 InMemoryDexClassLoader （ API 26 添加 ）。PathClassLoader 还有一个子类是 DelegateLastClassLoader （ API 27 添加 ）如果 jar 文件中包含 .dex 文件也是可以使用 BaseDexClassLoader 加载的那我们就分析一下 BaseDexClassLoader 的几个子类PathClassLoaderPathClassLoader 是一个简单的 ClassLoader 实现、Android 使用此类作为其系统类加载器和其应用程序类加载器。也就是说 PathClassLoader 在应用启动时创建，只能加载已经安装到 Android 系统中的apk文件（/data/app目录下，解压为 dex 后优化为 odex）。经过代码调用发现 PathClassLoader 的 parent 是 java.lang.BootClassLoader 这应该是最上层的 ClassLoader。DelegateLastClassLoaderDelegateLastClassLoader 是一个实现先查找再委托的类加载器实现protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { Class<?> cl = findLoadedClass(name); if (cl != null) { return cl; } try { return Object.class.getClassLoader().loadClass(name); } catch (ClassNotFoundException ignored) { } ClassNotFoundException fromSuper = null; try { return findClass(name); } catch (ClassNotFoundException ex) { fromSuper = ex; } try { return getParent().loadClass(name); } catch (ClassNotFoundException cnfe) { throw fromSuper; } }首先在当前加载器查找是否加载过这个类。然后，尝试搜索此类的类加载器是否加载过这个类。使用当前加载器尝试去加载类最后委托给父加载器加载。DexClassLoaderDexClassLoader 就不一样了他可以在可读取目录中加载 .dex 文件以及包含 .dex 的 .jar 、.zip 和 .apk 文件，比 PathClassLoader 更灵活，是实现热修复的关键。这个加载器只有一个构造方法 public DexClassLoader(String dexPath, String optimizedDirectory, String librarySearchPath, ClassLoader parent) 其中 optimizedDirectory 是用来缓存优化过的类或代码的， API 21 开始官方推荐放在 context.getCodeCacheDir() 目录InMemoryDexClassLoader他的作用可以直接加载内存中的 dex 文件2. 简述 ClassLoader 的双亲委托模型这个问题我们从源码入手protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { // 首先查找类是否加载过，加载过则返回类 Class c = findLoadedClass(name); if (c == null) { long t0 = System.nanoTime(); try { if (parent != null) { //让父类查找并加载类 c = parent.loadClass(name, false); } else { //查找由引导类加载器加载的类，如果未找到，则返回 NULL c = findBootstrapClassOrNull(name); } } catch (ClassNotFoundException e) { } if (c == null) { long t1 = System.nanoTime(); // c = findClass(name); } } return c; }（1）、首先查找当前类加载器是否加载过这个类，如果找到则返回这个类（2）、如果找不到，就会调用父类的方法去查找是否加载过这个类，如果父类没有加载过就去查找祖父类加载器是否加载过，按照这样的逻辑一直查找到最上层的类加载器（始祖类加载器），因为始祖加载器没有 parent 了，就用引导类加载器去查找。（3）、如果还没有找到就说明这个类 JVM 确实没有加载过，然后尝试使用引导类加载器加载这个类，如果成功则返回类，加载失败就再次尝试使用始祖类加载器，依次类推如果当前类加载器都加载失败则抛出异常小结：这样做保证的类只会加载一次3. 简述双亲委托模型在热修复领域的应用热修复的原理就是要替换类文件，Android 的虚拟机（ 基于寄存器 ）与 Java 的虚拟机（基于栈）有些不同，它加载的不是 .class 字节码，而是 .dex 文件（ 可以通过 Google 提供的 dx 工具对 .class 文件转换得到 ），所以上面提到的替换类文件就是等于替换 DEX 文件。通过 PathClassLoader 来加载我们自身 App 的 dex 文件。通过 DexClassLoader 来加载我们的没有 BUG 补丁dex 文件。首先通过反射拿到分别两个 ClassLoader 的 < DexPathList pathList > ( 一个是我们自己应用的,另一个是我们补丁的 )然后再次通过反射拿到分别两个 ClassLoader 中 pathList 里面的 <Element[] dexElements > 的值。合并两个反射到的 Element 数组。（ 需要把我们的补丁 dex 中的数组放在合并的数组最前面 ）将合并的新的数组，再次通过反射重新设置到我们自身 App 的 DexPathList 中，根据双亲委托模型类加载器会首先加载没有 BUG 的类