测试
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1,308 @@
|
||||
# PackageManagerService
|
||||
# PackageManagerService架构
|
||||
|
||||
PackageManagerService(PMS)是Android包管理系统的核心服务,负责应用的安装、卸载、更新和权限管理。本文深入分析PMS的架构设计、工作原理和关键实现。
|
||||
|
||||
## PMS系统架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "客户端层"
|
||||
A1[PackageManager] --> A2[IPackageManager]
|
||||
A2 --> A3[Binder通信]
|
||||
end
|
||||
|
||||
subgraph "服务端层"
|
||||
B1[PackageManagerService] --> B2[PackageParser]
|
||||
B2 --> B3[PackageSettings]
|
||||
B3 --> B4[Installer]
|
||||
|
||||
B1 --> B5[UserManagerService]
|
||||
B1 --> B6[ActivityManagerService]
|
||||
B1 --> B7[StorageManagerService]
|
||||
end
|
||||
|
||||
subgraph "数据层"
|
||||
C1[Package数据库] --> C2[Settings.xml]
|
||||
C2 --> C3[包目录结构]
|
||||
C3 --> C4[APK文件]
|
||||
end
|
||||
|
||||
A3 --> B1
|
||||
B4 --> C4
|
||||
```
|
||||
|
||||
## 1. PMS核心组件
|
||||
|
||||
### 1.1 PackageManagerService
|
||||
- **包管理**:管理所有应用的安装、卸载和更新
|
||||
- **权限管理**:管理应用权限的授予和撤销
|
||||
- **组件管理**:管理Activity、Service等组件信息
|
||||
- **包扫描**:扫描系统和应用目录中的APK文件
|
||||
|
||||
### 1.2 PackageParser
|
||||
- **APK解析**:解析APK文件的AndroidManifest.xml
|
||||
- **组件提取**:提取Activity、Service等组件信息
|
||||
- **资源解析**:解析APK中的资源信息
|
||||
- **签名验证**:验证APK的签名信息
|
||||
|
||||
### 1.3 PackageSettings
|
||||
- **包设置**:存储包的安装信息和设置
|
||||
- **用户管理**:管理多用户下的包状态
|
||||
- **权限状态**:存储权限授予状态
|
||||
- **包状态**:存储包的启用/禁用状态
|
||||
|
||||
## 2. 包安装流程
|
||||
|
||||
### 2.1 安装流程概览
|
||||
```java
|
||||
// PMS安装应用的关键流程
|
||||
public void installPackageAsUser(Uri packageUri, ...) {
|
||||
// 1. 权限检查
|
||||
enforcePermission(...);
|
||||
|
||||
// 2. 创建安装会话
|
||||
int sessionId = createInstallSession(...);
|
||||
|
||||
// 3. 写入APK文件
|
||||
writeApkToSession(sessionId, packageUri);
|
||||
|
||||
// 4. 提交安装
|
||||
commitSession(sessionId);
|
||||
|
||||
// 5. 解析APK
|
||||
PackageParser.Package pkg = parsePackage(...);
|
||||
|
||||
// 6. 验证签名
|
||||
verifySignatures(pkg);
|
||||
|
||||
// 7. 执行安装
|
||||
installPackageTracedLI(pkg, ...);
|
||||
|
||||
// 8. 发送广播
|
||||
sendPackageBroadcast(...);
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 APK解析过程
|
||||
```java
|
||||
// PackageParser解析APK
|
||||
public Package parsePackage(File apkFile, int flags) {
|
||||
// 1. 创建解析器
|
||||
PackageParser parser = new PackageParser();
|
||||
|
||||
// 2. 解析APK
|
||||
Package pkg = parser.parsePackage(apkFile, flags);
|
||||
|
||||
// 3. 收集组件信息
|
||||
collectCertificates(pkg);
|
||||
collectManifestDigest(pkg);
|
||||
|
||||
// 4. 提取四大组件
|
||||
extractActivities(pkg);
|
||||
extractServices(pkg);
|
||||
extractReceivers(pkg);
|
||||
extractProviders(pkg);
|
||||
|
||||
// 5. 提取权限信息
|
||||
extractPermissions(pkg);
|
||||
|
||||
return pkg;
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 包扫描机制
|
||||
|
||||
### 3.1 系统扫描
|
||||
- **系统目录扫描**:扫描/system/app、/system/priv-app等目录
|
||||
- **厂商目录扫描**:扫描/vendor/app等厂商目录
|
||||
- **OEM目录扫描**:扫描/oem/app等OEM目录
|
||||
|
||||
### 3.2 用户数据扫描
|
||||
- **用户安装目录**:扫描/data/app等用户安装目录
|
||||
- **用户数据目录**:扫描/data/user等用户数据目录
|
||||
- **外部存储扫描**:扫描外部存储中的APK文件
|
||||
|
||||
### 3.3 扫描优化
|
||||
```java
|
||||
// PMS包扫描优化策略
|
||||
class PackageManagerService {
|
||||
// 增量扫描:只扫描变化的目录
|
||||
void scanPackagesTracedLI(File scanDir, int scanFlags, ...) {
|
||||
// 1. 检查目录修改时间
|
||||
long lastModified = getLastModifiedTime(scanDir);
|
||||
if (lastModified <= mLastScanTime) {
|
||||
return; // 目录未修改,跳过扫描
|
||||
}
|
||||
|
||||
// 2. 增量扫描
|
||||
List<File> changedFiles = getChangedFiles(scanDir, mLastScanTime);
|
||||
for (File file : changedFiles) {
|
||||
scanPackageTracedLI(file, scanFlags, ...);
|
||||
}
|
||||
|
||||
// 3. 更新扫描时间
|
||||
mLastScanTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
// 并行扫描:多线程并行扫描
|
||||
void parallelScanPackages(List<File> scanDirs) {
|
||||
ExecutorService executor = Executors.newFixedThreadPool(4);
|
||||
List<Future<Package>> futures = new ArrayList<>();
|
||||
|
||||
for (File dir : scanDirs) {
|
||||
futures.add(executor.submit(() -> scanPackage(dir)));
|
||||
}
|
||||
|
||||
// 等待所有扫描完成
|
||||
for (Future<Package> future : futures) {
|
||||
Package pkg = future.get();
|
||||
addPackage(pkg);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 权限管理系统
|
||||
|
||||
### 4.1 权限分类
|
||||
- **普通权限**:不影响用户隐私的权限
|
||||
- **危险权限**:涉及用户隐私的权限
|
||||
- **签名权限**:需要相同签名的权限
|
||||
- **特殊权限**:系统特殊权限
|
||||
|
||||
### 4.2 权限授予流程
|
||||
```java
|
||||
// PMS权限授予流程
|
||||
public void grantRuntimePermission(String packageName, String permName, int userId) {
|
||||
// 1. 检查权限是否存在
|
||||
BasePermission bp = mSettings.mPermissions.get(permName);
|
||||
if (bp == null) {
|
||||
throw new SecurityException("Unknown permission: " + permName);
|
||||
}
|
||||
|
||||
// 2. 检查调用者权限
|
||||
enforceGrantRevokeRuntimePermissionPermissions(...);
|
||||
|
||||
// 3. 检查目标应用是否申请该权限
|
||||
PackageParser.Package pkg = getPackage(packageName);
|
||||
if (!pkg.requestedPermissions.contains(permName)) {
|
||||
throw new SecurityException("Package " + packageName + " has not requested permission " + permName);
|
||||
}
|
||||
|
||||
// 4. 授予权限
|
||||
PermissionState permState = mSettings.getPermissionState(permName, packageName, userId);
|
||||
permState.granted = true;
|
||||
permState.grantedFlags = flags;
|
||||
|
||||
// 5. 更新权限状态
|
||||
updatePermissions(packageName, pkg);
|
||||
|
||||
// 6. 发送广播通知
|
||||
sendPackageChangedBroadcast(packageName, userId);
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 多用户支持
|
||||
|
||||
### 5.1 用户隔离
|
||||
- **用户ID**:每个用户有唯一的用户ID
|
||||
- **数据隔离**:不同用户的数据完全隔离
|
||||
- **权限隔离**:不同用户的权限状态独立
|
||||
|
||||
### 5.2 用户管理
|
||||
```java
|
||||
// PMS多用户管理
|
||||
class PackageManagerService {
|
||||
// 用户包状态管理
|
||||
final SparseArray<PackageSetting> mSettingsByUser = new SparseArray<>();
|
||||
|
||||
// 为用户安装包
|
||||
void installPackageAsUser(String packageName, int userId) {
|
||||
// 1. 获取主用户包信息
|
||||
PackageSetting ps = getPackageSetting(packageName, UserHandle.USER_SYSTEM);
|
||||
|
||||
// 2. 为用户创建包状态
|
||||
PackageSetting userPs = createPackageSettingForUser(ps, userId);
|
||||
|
||||
// 3. 设置用户包状态
|
||||
mSettingsByUser.put(userId, userPs);
|
||||
|
||||
// 4. 创建用户数据目录
|
||||
createUserDataIfNeeded(packageName, userId);
|
||||
}
|
||||
|
||||
// 删除用户包
|
||||
void removePackageAsUser(String packageName, int userId) {
|
||||
// 1. 删除用户包状态
|
||||
mSettingsByUser.remove(userId);
|
||||
|
||||
// 2. 删除用户数据目录
|
||||
deleteUserData(packageName, userId);
|
||||
|
||||
// 3. 清理缓存
|
||||
clearPackagePreferredActivities(packageName, userId);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 性能优化
|
||||
|
||||
### 6.1 启动优化
|
||||
- **延迟扫描**:非关键目录延迟扫描
|
||||
- **并行解析**:多APK并行解析
|
||||
- **缓存机制**:缓存已解析的包信息
|
||||
|
||||
### 6.2 内存优化
|
||||
- **对象复用**:复用PackageParser等对象
|
||||
- **懒加载**:按需加载包信息
|
||||
- **资源释放**:及时释放不再使用的资源
|
||||
|
||||
### 6.3 存储优化
|
||||
- **增量更新**:只更新变化的包信息
|
||||
- **压缩存储**:压缩存储包元数据
|
||||
- **索引优化**:优化包查询索引
|
||||
|
||||
## 7. 调试与问题排查
|
||||
|
||||
### 7.1 调试工具
|
||||
```bash
|
||||
# 查看包信息
|
||||
adb shell dumpsys package <package_name>
|
||||
|
||||
# 查看权限信息
|
||||
adb shell dumpsys package permissions
|
||||
|
||||
# 查看安装会话
|
||||
adb shell dumpsys package sessions
|
||||
|
||||
# 查看包管理器状态
|
||||
adb shell dumpsys package
|
||||
|
||||
# 性能分析
|
||||
adb shell dumpsys package --timing
|
||||
```
|
||||
|
||||
### 7.2 常见问题
|
||||
- **安装失败**:签名验证失败、存储空间不足等
|
||||
- **权限问题**:权限未正确授予或撤销
|
||||
- **包冲突**:相同包名或签名的包冲突
|
||||
- **扫描问题**:APK文件损坏或格式错误
|
||||
- **性能问题**:包扫描或解析耗时过长
|
||||
|
||||
### 7.3 问题排查步骤
|
||||
1. **收集日志**:查看logcat中的PMS相关日志
|
||||
2. **检查状态**:使用dumpsys命令检查包状态
|
||||
3. **验证APK**:检查APK文件完整性和签名
|
||||
4. **分析配置**:检查系统配置和权限设置
|
||||
5. **性能分析**:使用性能分析工具定位瓶颈
|
||||
|
||||
## 总结
|
||||
|
||||
PackageManagerService是Android系统的核心服务:
|
||||
- **应用管理**:统一管理所有应用的安装和卸载
|
||||
- **权限控制**:严格控制应用权限的授予和使用
|
||||
- **组件管理**:管理应用组件的注册和发现
|
||||
- **多用户支持**:支持多用户环境下的应用隔离
|
||||
- **系统稳定**:确保应用安装和运行的稳定性
|
||||
|
||||
深入理解PackageManagerService架构,对于优化应用安装体验、排查包管理问题和设计系统级功能具有重要意义。
|
||||
@@ -1 +1,143 @@
|
||||
# 04-资源与包管理
|
||||
# 04-资源与包管理
|
||||
|
||||
本目录包含Android Framework中资源管理与包管理的核心知识和技术文档。资源管理和包管理是Android系统的基础功能,直接影响应用的安装、运行和用户体验。
|
||||
|
||||
## 文档结构
|
||||
|
||||
### 1. 动态加载与热修复原理.md
|
||||
- **内容**:深入分析Android动态加载和热修复技术的原理与实现
|
||||
- **重点**:插件化架构、热修复方案、资源合并、So库修复
|
||||
- **适用**:需要实现应用热更新和插件化架构的开发者
|
||||
|
||||
### 2. PackageManagerService.md
|
||||
- **内容**:全面分析PackageManagerService的架构设计和工作原理
|
||||
- **重点**:包安装流程、权限管理、包扫描机制、多用户支持
|
||||
- **适用**:需要深入理解Android包管理机制的开发者
|
||||
|
||||
### 3. Resource资源加载机制.md
|
||||
- **内容**:详细分析Android资源系统的加载机制和优化策略
|
||||
- **重点**:资源编译、资源查找、资源缓存、多语言支持
|
||||
- **适用**:需要优化资源加载性能和实现动态换肤的开发者
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 资源管理系统
|
||||
- **资源编译**:aapt2将资源编译为二进制格式
|
||||
- **资源打包**:资源打包到APK的resources.arsc
|
||||
- **资源查找**:通过Resource ID查找对应资源
|
||||
- **资源缓存**:缓存已加载的资源提高性能
|
||||
|
||||
### 包管理系统
|
||||
- **APK结构**:Dex文件、资源文件、Native库、清单文件
|
||||
- **包安装**:验证、解析、复制、优化、注册
|
||||
- **权限管理**:权限分类、授予、检查、撤销
|
||||
- **组件管理**:Activity、Service、Receiver、Provider注册
|
||||
|
||||
### 动态加载系统
|
||||
- **类加载**:DexClassLoader、PathClassLoader
|
||||
- **资源合并**:AssetManager多路径加载
|
||||
- **热修复**:方法替换、类替换、资源替换
|
||||
- **插件化**:插件生命周期、组件代理、通信机制
|
||||
|
||||
## 技术要点
|
||||
|
||||
### 1. 性能优化
|
||||
- **资源优化**:减少资源大小、使用WebP格式、资源压缩
|
||||
- **包优化**:减少APK大小、使用App Bundle、动态交付
|
||||
- **加载优化**:懒加载、预加载、缓存策略
|
||||
|
||||
### 2. 安全考虑
|
||||
- **签名验证**:验证APK签名防止篡改
|
||||
- **权限控制**:最小权限原则、运行时权限
|
||||
- **代码保护**:代码混淆、资源加密、反调试
|
||||
|
||||
### 3. 兼容性处理
|
||||
- **版本适配**:处理不同Android版本的API差异
|
||||
- **厂商适配**:处理各厂商的系统定制问题
|
||||
- **架构适配**:支持不同CPU架构和屏幕密度
|
||||
|
||||
## 调试工具
|
||||
|
||||
### 常用命令
|
||||
```bash
|
||||
# 查看包信息
|
||||
adb shell dumpsys package <package_name>
|
||||
adb shell pm list packages
|
||||
adb shell pm path <package_name>
|
||||
|
||||
# 查看资源信息
|
||||
adb shell dumpsys resources
|
||||
adb shell getprop | grep density
|
||||
adb shell wm size
|
||||
|
||||
# 查看安装信息
|
||||
adb shell dumpsys package installs
|
||||
adb shell dumpsys package sessions
|
||||
|
||||
# 性能分析
|
||||
adb shell dumpsys package --timing
|
||||
adb shell am profile start <process> <trace_file>
|
||||
```
|
||||
|
||||
### 开发者工具
|
||||
- **Android Studio Profiler**:分析资源使用和性能
|
||||
- **Layout Inspector**:查看界面布局和资源
|
||||
- **APK Analyzer**:分析APK结构和资源
|
||||
- **Systrace/Perfetto**:性能跟踪和分析
|
||||
|
||||
## 学习路径
|
||||
|
||||
### 初级开发者
|
||||
1. 理解Android资源系统和包管理基本概念
|
||||
2. 掌握资源使用和权限申请
|
||||
3. 学会基本的APK分析和优化
|
||||
|
||||
### 中级开发者
|
||||
1. 深入理解PackageManagerService架构
|
||||
2. 掌握资源加载和热修复原理
|
||||
3. 学会插件化架构设计和实现
|
||||
|
||||
### 高级开发者
|
||||
1. 理解系统底层资源管理和包管理机制
|
||||
2. 掌握性能优化和安全加固技术
|
||||
3. 能够设计和实现复杂的动态加载系统
|
||||
|
||||
## 相关资源
|
||||
|
||||
### 官方文档
|
||||
- [Android Developers - App Resources](https://developer.android.com/guide/topics/resources)
|
||||
- [Android Developers - App Manifest](https://developer.android.com/guide/topics/manifest)
|
||||
- [Android Developers - Permissions](https://developer.android.com/guide/topics/permissions)
|
||||
- [Android Developers - Dynamic Delivery](https://developer.android.com/guide/app-bundle)
|
||||
|
||||
### 开源项目
|
||||
- [Android Open Source Project - PackageManagerService](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/pm/)
|
||||
- [Android Open Source Project - Resource Manager](https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/content/res/)
|
||||
- [Tinker - 热修复框架](https://github.com/Tencent/tinker)
|
||||
- [VirtualAPK - 插件化框架](https://github.com/didi/VirtualAPK)
|
||||
|
||||
### 工具资源
|
||||
- [Android Asset Packaging Tool 2 (aapt2)](https://developer.android.com/studio/command-line/aapt2)
|
||||
- [APK Analyzer](https://developer.android.com/studio/build/apk-analyzer)
|
||||
- [Bundletool](https://developer.android.com/studio/command-line/bundletool)
|
||||
- [AndResGuard - 资源混淆工具](https://github.com/shwenzhang/AndResGuard)
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 2026-01-12
|
||||
- 完善所有文档内容,使用标准Markdown格式
|
||||
- 添加详细的技术分析和最佳实践
|
||||
- 补充调试工具和问题排查方法
|
||||
- 更新相关资源和学习路径
|
||||
|
||||
## 贡献指南
|
||||
|
||||
欢迎对本目录的文档进行改进和补充:
|
||||
1. 确保内容准确、技术正确,反映最新Android版本特性
|
||||
2. 使用标准的Markdown格式,保持文档结构清晰
|
||||
3. 添加实际代码示例和最佳实践,便于读者理解
|
||||
4. 保持文档的实用性和可读性,避免过于理论化
|
||||
|
||||
---
|
||||
|
||||
*本目录文档将持续更新,以反映Android Framework的最新发展和最佳实践。*
|
||||
@@ -1 +1,370 @@
|
||||
# Resource资源加载机制
|
||||
# Resource资源加载机制
|
||||
|
||||
Android资源系统是应用界面和功能的基础,负责管理字符串、图片、布局等所有资源。本文深入分析Android资源系统的加载机制、优化策略和最佳实践。
|
||||
|
||||
## 资源系统架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "编译阶段"
|
||||
A1[资源文件] --> A2[aapt2编译]
|
||||
A2 --> A3[resources.arsc]
|
||||
A3 --> A4[APK包]
|
||||
end
|
||||
|
||||
subgraph "运行阶段"
|
||||
B1[APK包] --> B2[AssetManager]
|
||||
B2 --> B3[Resources]
|
||||
B3 --> B4[ResourceTable]
|
||||
|
||||
B2 --> B5[资源缓存]
|
||||
B3 --> B6[Configuration]
|
||||
B4 --> B7[资源查找]
|
||||
end
|
||||
|
||||
subgraph "应用层"
|
||||
C1[Activity] --> C2[getResources]
|
||||
C2 --> C3[资源访问]
|
||||
C3 --> C4[界面渲染]
|
||||
end
|
||||
|
||||
A4 --> B1
|
||||
B7 --> C3
|
||||
```
|
||||
|
||||
## 1. 资源编译与打包
|
||||
|
||||
### 1.1 资源编译流程
|
||||
- **aapt2编译**:将XML和图片资源编译为二进制格式
|
||||
- **资源链接**:将所有资源链接到resources.arsc
|
||||
- **资源优化**:优化资源大小和加载效率
|
||||
|
||||
### 1.2 resources.arsc结构
|
||||
```cpp
|
||||
// resources.arsc文件结构
|
||||
struct ResTable_header {
|
||||
struct ResChunk_header header; // 块头信息
|
||||
uint32_t packageCount; // 包数量
|
||||
};
|
||||
|
||||
struct ResTable_package {
|
||||
struct ResChunk_header header; // 包头信息
|
||||
uint32_t id; // 包ID
|
||||
char16_t name[128]; // 包名
|
||||
uint32_t typeStrings; // 类型字符串偏移
|
||||
uint32_t lastPublicType; // 最后公共类型
|
||||
uint32_t keyStrings; // 键字符串偏移
|
||||
uint32_t lastPublicKey; // 最后公共键
|
||||
uint32_t typeIdOffset; // 类型ID偏移
|
||||
};
|
||||
```
|
||||
|
||||
### 1.3 资源ID结构
|
||||
```
|
||||
0xPPTTEEEE
|
||||
PP (1字节): Package ID (0x01: 系统资源, 0x7F: 应用资源)
|
||||
TT (1字节): Type ID (资源类型: 0x01: anim, 0x02: attr等)
|
||||
EEEE (2字节): Entry ID (资源条目ID)
|
||||
```
|
||||
|
||||
## 2. 资源加载机制
|
||||
|
||||
### 2.1 AssetManager初始化
|
||||
```java
|
||||
// AssetManager初始化流程
|
||||
public AssetManager() {
|
||||
// 1. 创建Native对象
|
||||
mObject = nativeCreate();
|
||||
|
||||
// 2. 添加资源路径
|
||||
addAssetPath(getPackageResourcePath());
|
||||
|
||||
// 3. 确保资源表已加载
|
||||
ensureStringBlocks();
|
||||
}
|
||||
|
||||
// 添加资源路径
|
||||
public int addAssetPath(String path) {
|
||||
synchronized (this) {
|
||||
// 调用Native方法添加资源路径
|
||||
int res = addAssetPathNative(path);
|
||||
makeStringBlocks(mStringBlocks);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Resources创建
|
||||
```java
|
||||
// Resources创建流程
|
||||
public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
|
||||
mAssets = assets;
|
||||
mMetrics = metrics;
|
||||
mConfiguration = config;
|
||||
|
||||
// 更新配置
|
||||
updateConfiguration(config, metrics);
|
||||
|
||||
// 创建兼容性信息
|
||||
mCompatibilityInfo = compatibilityInfo;
|
||||
|
||||
// 初始化资源实现
|
||||
mResourcesImpl = new ResourcesImpl(assets, metrics, config, compatibilityInfo);
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 资源查找流程
|
||||
|
||||
### 3.1 资源查找算法
|
||||
```cpp
|
||||
// Native层资源查找
|
||||
status_t AssetManager::getResourceValue(
|
||||
uint32_t resID, Res_value* outValue, bool mayBeBag, uint16_t density) {
|
||||
// 1. 解析资源ID
|
||||
const uint32_t packageId = getPackageId(resID);
|
||||
const uint32_t typeId = getTypeId(resID);
|
||||
const uint32_t entryId = getEntryId(resID);
|
||||
|
||||
// 2. 查找包
|
||||
const Package* package = getPackage(packageId);
|
||||
if (package == NULL) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// 3. 查找类型
|
||||
const Type* type = package->getType(typeId, density);
|
||||
if (type == NULL) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// 4. 查找条目
|
||||
const Entry* entry = type->getEntry(entryId);
|
||||
if (entry == NULL) {
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// 5. 返回值
|
||||
*outValue = entry->getValue();
|
||||
return NO_ERROR;
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 资源缓存机制
|
||||
```java
|
||||
// Resources中的资源缓存
|
||||
class Resources {
|
||||
// 资源缓存
|
||||
private final LongSparseArray<Drawable.ConstantState> mDrawableCache;
|
||||
private final LongSparseArray<ColorStateList> mColorStateListCache;
|
||||
private final LongSparseArray<ComplexColor> mComplexColorCache;
|
||||
|
||||
// 获取Drawable(带缓存)
|
||||
public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) {
|
||||
// 1. 检查缓存
|
||||
final long key = (((long) theme) << 32) | ((long) id);
|
||||
Drawable.ConstantState cs = mDrawableCache.get(key);
|
||||
if (cs != null) {
|
||||
return cs.newDrawable(this);
|
||||
}
|
||||
|
||||
// 2. 加载资源
|
||||
TypedValue value = new TypedValue();
|
||||
getValue(id, value, true);
|
||||
|
||||
// 3. 创建Drawable
|
||||
Drawable dr = loadDrawable(value, id, theme);
|
||||
|
||||
// 4. 放入缓存
|
||||
if (dr != null && dr.getConstantState() != null) {
|
||||
mDrawableCache.put(key, dr.getConstantState());
|
||||
}
|
||||
|
||||
return dr;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 多配置支持
|
||||
|
||||
### 4.1 配置限定符
|
||||
- **语言区域**:zh、en、fr等
|
||||
- **屏幕方向**:port、land
|
||||
- **屏幕密度**:ldpi、mdpi、hdpi、xhdpi等
|
||||
- **屏幕尺寸**:small、normal、large、xlarge
|
||||
- **API级别**:v21、v23等
|
||||
|
||||
### 4.2 配置匹配算法
|
||||
```java
|
||||
// 配置匹配算法
|
||||
public Configuration findBestConfig(Configuration config, Configuration[] configs) {
|
||||
Configuration bestConfig = null;
|
||||
int bestScore = Integer.MIN_VALUE;
|
||||
|
||||
for (Configuration candidate : configs) {
|
||||
// 计算匹配分数
|
||||
int score = config.match(candidate);
|
||||
|
||||
// 选择最高分
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestConfig = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return bestConfig;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 动态资源加载
|
||||
|
||||
### 5.1 皮肤切换
|
||||
```java
|
||||
// 动态换肤实现
|
||||
public class SkinManager {
|
||||
private AssetManager mAssetManager;
|
||||
private Resources mResources;
|
||||
private String mSkinPath;
|
||||
|
||||
// 加载皮肤
|
||||
public void loadSkin(String skinPath) {
|
||||
try {
|
||||
// 1. 创建新的AssetManager
|
||||
mAssetManager = AssetManager.class.newInstance();
|
||||
|
||||
// 2. 添加皮肤资源路径
|
||||
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
|
||||
addAssetPath.invoke(mAssetManager, skinPath);
|
||||
|
||||
// 3. 创建新的Resources
|
||||
Resources superRes = getResources();
|
||||
mResources = new Resources(mAssetManager,
|
||||
superRes.getDisplayMetrics(),
|
||||
superRes.getConfiguration());
|
||||
|
||||
mSkinPath = skinPath;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取皮肤资源
|
||||
public Resources getSkinResources() {
|
||||
return mResources;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.2 插件资源合并
|
||||
```java
|
||||
// 插件资源合并
|
||||
public class PluginResourceManager {
|
||||
private AssetManager mHostAssetManager;
|
||||
private List<AssetManager> mPluginAssetManagers = new ArrayList<>();
|
||||
|
||||
// 合并插件资源
|
||||
public void mergePluginResources(String pluginApkPath) {
|
||||
try {
|
||||
// 1. 创建插件AssetManager
|
||||
AssetManager pluginAssetManager = AssetManager.class.newInstance();
|
||||
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
|
||||
addAssetPath.invoke(pluginAssetManager, pluginApkPath);
|
||||
|
||||
// 2. 添加到列表
|
||||
mPluginAssetManagers.add(pluginAssetManager);
|
||||
|
||||
// 3. 创建合并的Resources
|
||||
Resources mergedResources = createMergedResources();
|
||||
|
||||
// 4. 更新应用Resources
|
||||
updateApplicationResources(mergedResources);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建合并的Resources
|
||||
private Resources createMergedResources() {
|
||||
// 合并所有AssetManager的资源
|
||||
// 注意:需要处理资源ID冲突
|
||||
return new MergedResources(mHostAssetManager, mPluginAssetManagers);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 6. 性能优化
|
||||
|
||||
### 6.1 资源优化策略
|
||||
- **资源压缩**:使用WebP格式、压缩PNG
|
||||
- **资源分包**:按需加载资源包
|
||||
- **资源缓存**:合理设置缓存大小和策略
|
||||
- **懒加载**:按需加载大资源
|
||||
|
||||
### 6.2 内存优化
|
||||
```java
|
||||
// 资源内存优化
|
||||
class ResourceMemoryOptimizer {
|
||||
// 监控资源内存使用
|
||||
public void monitorResourceMemory() {
|
||||
// 1. 获取当前内存状态
|
||||
Debug.MemoryInfo memoryInfo = new Debug.MemoryInfo();
|
||||
Debug.getMemoryInfo(memoryInfo);
|
||||
|
||||
// 2. 检查资源缓存大小
|
||||
long drawableCacheSize = calculateDrawableCacheSize();
|
||||
long colorCacheSize = calculateColorCacheSize();
|
||||
|
||||
// 3. 根据内存压力调整缓存
|
||||
if (memoryInfo.getTotalPss() > MEMORY_THRESHOLD) {
|
||||
clearUnusedResources();
|
||||
shrinkResourceCaches();
|
||||
}
|
||||
}
|
||||
|
||||
// 清理未使用资源
|
||||
private void clearUnusedResources() {
|
||||
// 清理长时间未使用的资源
|
||||
// 根据LRU算法清理缓存
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 7. 调试与问题排查
|
||||
|
||||
### 7.1 调试工具
|
||||
```bash
|
||||
# 查看资源信息
|
||||
adb shell dumpsys resources
|
||||
adb shell dumpsys meminfo <package_name> | grep -A 10 "Asset Allocations"
|
||||
|
||||
# 查看当前配置
|
||||
adb shell getprop | grep -E "(density|locale|orientation)"
|
||||
adb shell wm size
|
||||
adb shell wm density
|
||||
|
||||
# 性能分析
|
||||
adb shell am dumpheap <process> <heap_file>
|
||||
adb shell am profile start <process> <trace_file>
|
||||
```
|
||||
|
||||
### 7.2 常见问题
|
||||
- **资源找不到**:资源ID错误、资源未编译、配置不匹配
|
||||
- **内存泄漏**:资源未正确释放、缓存过大
|
||||
- **性能问题**:资源加载过慢、缓存命中率低
|
||||
- **兼容性问题**:不同设备配置资源不匹配
|
||||
|
||||
### 7.3 问题排查步骤
|
||||
1. **检查资源ID**:确认资源ID是否正确
|
||||
2. **检查资源配置**:确认设备配置和资源匹配
|
||||
3. **检查资源文件**:确认资源文件存在且格式正确
|
||||
4. **分析内存使用**:检查资源内存占用情况
|
||||
5. **性能分析**:使用性能分析工具定位瓶颈
|
||||
|
||||
## 总结
|
||||
|
||||
Android资源系统是应用开发的基础:
|
||||
- **高效加载**:二进制格式和缓存机制确保高效加载
|
||||
- **灵活配置**:多配置支持适应不同设备和场景
|
||||
- **动态扩展**:支持皮肤切换和插件资源合并
|
||||
- **性能优化**:多种优化策略确保良好性能
|
||||
|
||||
深入理解Resource资源加载机制,对于优化应用性能、实现动态换肤和设计插件化架构具有重要意义。
|
||||
@@ -1 +1,249 @@
|
||||
# 动态加载与热修复原理
|
||||
# 动态加载与热修复原理
|
||||
|
||||
Android动态加载和热修复技术允许应用在不重新安装的情况下更新代码和资源,提升用户体验和开发效率。本文深入分析动态加载和热修复的核心原理、实现方案和最佳实践。
|
||||
|
||||
## 技术架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "动态加载"
|
||||
A1[宿主应用] --> A2[DexClassLoader]
|
||||
A2 --> A3[插件APK]
|
||||
A3 --> A4[插件资源]
|
||||
A4 --> A5[插件Activity]
|
||||
end
|
||||
|
||||
subgraph "热修复"
|
||||
B1[原始类] --> B2[补丁类]
|
||||
B2 --> B3[类加载替换]
|
||||
B3 --> B4[方法替换]
|
||||
B4 --> B5[即时生效]
|
||||
end
|
||||
|
||||
subgraph "资源管理"
|
||||
C1[AssetManager] --> C2[资源合并]
|
||||
C2 --> C3[资源重定向]
|
||||
C3 --> C4[资源隔离]
|
||||
end
|
||||
```
|
||||
|
||||
## 1. 动态加载技术
|
||||
|
||||
### 1.1 类加载机制
|
||||
- **双亲委派模型**:ClassLoader的类加载机制
|
||||
- **DexClassLoader**:支持从APK/JAR文件加载Dex
|
||||
- **PathClassLoader**:系统默认的ClassLoader
|
||||
|
||||
### 1.2 插件化架构
|
||||
```java
|
||||
// 插件化核心代码示例
|
||||
public class PluginManager {
|
||||
private DexClassLoader mClassLoader;
|
||||
private AssetManager mAssetManager;
|
||||
private Resources mResources;
|
||||
|
||||
// 加载插件
|
||||
public void loadPlugin(String apkPath) {
|
||||
// 1. 创建DexClassLoader
|
||||
mClassLoader = new DexClassLoader(
|
||||
apkPath, // APK路径
|
||||
getDir("dex", 0).getPath(), // 优化后的Dex输出目录
|
||||
null, // 库文件目录
|
||||
getClassLoader() // 父ClassLoader
|
||||
);
|
||||
|
||||
// 2. 创建AssetManager加载插件资源
|
||||
mAssetManager = AssetManager.class.newInstance();
|
||||
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
|
||||
addAssetPath.invoke(mAssetManager, apkPath);
|
||||
|
||||
// 3. 创建Resources对象
|
||||
Resources superRes = getResources();
|
||||
mResources = new Resources(mAssetManager, superRes.getDisplayMetrics(), superRes.getConfiguration());
|
||||
}
|
||||
|
||||
// 加载插件类
|
||||
public Class<?> loadClass(String className) throws ClassNotFoundException {
|
||||
return mClassLoader.loadClass(className);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 热修复技术
|
||||
|
||||
### 2.1 热修复原理
|
||||
- **方法替换**:运行时替换有问题的Java方法
|
||||
- **类加载替换**:替换ClassLoader加载的类
|
||||
- **Native修复**:修复Native层的代码问题
|
||||
|
||||
### 2.2 主流方案对比
|
||||
|
||||
| 方案 | 原理 | 优点 | 缺点 |
|
||||
|------|------|------|------|
|
||||
| **AndFix** | Native方法替换 | 即时生效,兼容性好 | 需要适配不同Android版本 |
|
||||
| **Tinker** | 全量Dex替换 | 修复彻底,支持资源修复 | 需要重启应用 |
|
||||
| **Sophix** | 混合模式 | 即时生效+全量替换 | 商业方案,需要付费 |
|
||||
| **Robust** | Instant Run原理 | 稳定性高 | 方法插桩,包体积增大 |
|
||||
|
||||
### 2.3 Tinker实现原理
|
||||
```java
|
||||
// Tinker核心原理:Dex差分合并
|
||||
public class TinkerManager {
|
||||
// 1. 生成差分包
|
||||
public void generatePatch(String oldApk, String newApk, String patchPath) {
|
||||
// 使用BSDiff算法生成Dex差分
|
||||
BsDiff.diff(oldApk, newApk, patchPath);
|
||||
}
|
||||
|
||||
// 2. 应用补丁
|
||||
public void applyPatch(Context context, String patchPath) {
|
||||
// 加载补丁Dex
|
||||
DexClassLoader patchClassLoader = new DexClassLoader(
|
||||
patchPath,
|
||||
context.getDir("patch", 0).getPath(),
|
||||
null,
|
||||
PathClassLoader.getSystemClassLoader()
|
||||
);
|
||||
|
||||
// 合并到主DexClassLoader
|
||||
mergeDexElements(patchClassLoader, context.getClassLoader());
|
||||
}
|
||||
|
||||
// 3. 合并DexElements
|
||||
private void mergeDexElements(ClassLoader patchLoader, ClassLoader mainLoader) {
|
||||
// 通过反射合并DexPathList中的dexElements数组
|
||||
// 将补丁Dex插入到数组最前面,优先加载
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 资源热修复
|
||||
|
||||
### 3.1 资源加载机制
|
||||
- **AssetManager**:Android资源管理核心类
|
||||
- **Resources**:资源访问接口
|
||||
- **ResourceTable**:资源ID映射表
|
||||
|
||||
### 3.2 资源合并方案
|
||||
```java
|
||||
// 资源合并实现
|
||||
public class ResourceManager {
|
||||
private AssetManager mAssetManager;
|
||||
private Resources mResources;
|
||||
|
||||
// 合并插件资源
|
||||
public void mergeResources(String pluginApkPath) {
|
||||
try {
|
||||
// 1. 创建新的AssetManager
|
||||
mAssetManager = AssetManager.class.newInstance();
|
||||
|
||||
// 2. 添加宿主资源路径
|
||||
Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
|
||||
addAssetPath.invoke(mAssetManager, getPackageResourcePath());
|
||||
|
||||
// 3. 添加插件资源路径
|
||||
addAssetPath.invoke(mAssetManager, pluginApkPath);
|
||||
|
||||
// 4. 创建新的Resources
|
||||
Resources superRes = getResources();
|
||||
mResources = new Resources(mAssetManager,
|
||||
superRes.getDisplayMetrics(),
|
||||
superRes.getConfiguration());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// 获取合并后的资源
|
||||
public Resources getResources() {
|
||||
return mResources;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. So库热修复
|
||||
|
||||
### 4.1 So库加载机制
|
||||
- **System.loadLibrary**:加载系统库
|
||||
- **System.load**:加载指定路径的库
|
||||
- **NativeLoader**:Android系统的Native加载器
|
||||
|
||||
### 4.2 So库替换方案
|
||||
```java
|
||||
// So库热修复实现
|
||||
public class SoHotFix {
|
||||
// 加载补丁So库
|
||||
public static void loadPatchSo(String soPath) {
|
||||
try {
|
||||
// 1. 获取系统的NativeLibrary路径
|
||||
Field libraryPathField = ClassLoader.class.getDeclaredField("libraryPath");
|
||||
libraryPathField.setAccessible(true);
|
||||
|
||||
// 2. 添加补丁So库路径
|
||||
String oldPath = (String) libraryPathField.get(ClassLoader.getSystemClassLoader());
|
||||
String newPath = soPath + File.pathSeparator + oldPath;
|
||||
libraryPathField.set(ClassLoader.getSystemClassLoader(), newPath);
|
||||
|
||||
// 3. 重新加载So库
|
||||
System.loadLibrary("patched_lib");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 性能与兼容性
|
||||
|
||||
### 5.1 性能优化
|
||||
- **懒加载**:按需加载插件组件
|
||||
- **缓存机制**:缓存已加载的类和资源
|
||||
- **预加载**:提前加载常用插件
|
||||
|
||||
### 5.2 兼容性处理
|
||||
- **API适配**:处理不同Android版本的API差异
|
||||
- **厂商适配**:处理各厂商的系统定制问题
|
||||
- **架构适配**:支持ARM、x86等不同CPU架构
|
||||
|
||||
## 6. 安全考虑
|
||||
|
||||
### 6.1 安全风险
|
||||
- **代码注入**:恶意插件注入危险代码
|
||||
- **资源劫持**:插件劫持宿主资源
|
||||
- **数据泄露**:插件访问敏感数据
|
||||
|
||||
### 6.2 安全措施
|
||||
- **签名验证**:验证插件签名合法性
|
||||
- **权限控制**:限制插件权限范围
|
||||
- **沙箱隔离**:插件运行在隔离环境
|
||||
|
||||
## 7. 调试与问题排查
|
||||
|
||||
### 7.1 调试工具
|
||||
```bash
|
||||
# 查看ClassLoader信息
|
||||
adb shell dumpsys activity top | grep -A 20 "ClassLoader"
|
||||
|
||||
# 查看Dex文件信息
|
||||
adb shell dex2oat --dex-file=<dex_path> --oat-file=<oat_path>
|
||||
|
||||
# 性能分析
|
||||
adb shell am profile start <process> <trace_file>
|
||||
adb shell am profile stop <process>
|
||||
```
|
||||
|
||||
### 7.2 常见问题
|
||||
- **类找不到**:ClassLoader加载路径问题
|
||||
- **资源冲突**:资源ID重复或冲突
|
||||
- **内存泄漏**:插件未正确释放资源
|
||||
- **兼容性问题**:特定机型或系统版本问题
|
||||
|
||||
## 总结
|
||||
|
||||
动态加载与热修复是Android高级开发的重要技术:
|
||||
- **灵活更新**:实现应用的不重启更新
|
||||
- **快速修复**:及时修复线上问题
|
||||
- **模块化开发**:支持插件化架构
|
||||
- **用户体验**:提升用户使用体验
|
||||
|
||||
深入理解动态加载与热修复原理,对于构建稳定、可维护的Android应用具有重要意义。
|
||||
@@ -1 +1,555 @@
|
||||
# AIDL与HIDL使用与原理
|
||||
|
||||
在Android系统中,AIDL(Android Interface Definition Language)和HIDL(Hardware Interface Definition Language)是两种重要的跨进程通信机制。本文深入分析它们的原理、使用方法和最佳实践。
|
||||
|
||||
## 架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "AIDL架构"
|
||||
A1[客户端 Client] --> A2[代理 Proxy]
|
||||
A2 --> A3[服务端 Service]
|
||||
A3 --> A4[Binder驱动]
|
||||
A4 --> A5[系统服务]
|
||||
end
|
||||
|
||||
subgraph "HIDL架构"
|
||||
B1[HAL层] --> B2[HIDL接口]
|
||||
B2 --> B3[Framework层]
|
||||
B3 --> B4[应用层]
|
||||
B4 --> B5[硬件抽象]
|
||||
end
|
||||
|
||||
subgraph "通信流程"
|
||||
C1[接口定义] --> C2[代码生成]
|
||||
C2 --> C3[服务实现]
|
||||
C3 --> C4[客户端调用]
|
||||
C4 --> C5[数据传输]
|
||||
end
|
||||
```
|
||||
|
||||
## 1. AIDL基础
|
||||
|
||||
### 1.1 AIDL接口定义
|
||||
```java
|
||||
// IBookManager.aidl
|
||||
package com.example.aidl;
|
||||
|
||||
// 导入其他AIDL接口
|
||||
import com.example.aidl.IBookListener;
|
||||
|
||||
// 定义接口
|
||||
interface IBookManager {
|
||||
// 基本数据类型
|
||||
int getBookCount();
|
||||
|
||||
// 自定义对象(需要实现Parcelable)
|
||||
Book getBook(in int bookId);
|
||||
|
||||
// 对象列表
|
||||
List<Book> getBookList();
|
||||
|
||||
// 添加书籍
|
||||
void addBook(in Book book);
|
||||
|
||||
// 注册监听器(oneway表示异步调用)
|
||||
oneway void registerListener(IBookListener listener);
|
||||
|
||||
// 注销监听器
|
||||
oneway void unregisterListener(IBookListener listener);
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 Parcelable对象定义
|
||||
```java
|
||||
// Book.java - 实现Parcelable接口
|
||||
public class Book implements Parcelable {
|
||||
private int id;
|
||||
private String name;
|
||||
private double price;
|
||||
|
||||
// Parcelable实现
|
||||
protected Book(Parcel in) {
|
||||
id = in.readInt();
|
||||
name = in.readString();
|
||||
price = in.readDouble();
|
||||
}
|
||||
|
||||
public static final Creator<Book> CREATOR = new Creator<Book>() {
|
||||
@Override
|
||||
public Book createFromParcel(Parcel in) {
|
||||
return new Book(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book[] newArray(int size) {
|
||||
return new Book[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(id);
|
||||
dest.writeString(name);
|
||||
dest.writeDouble(price);
|
||||
}
|
||||
|
||||
// 对应Book.aidl文件
|
||||
// parcelable Book;
|
||||
}
|
||||
```
|
||||
|
||||
## 2. AIDL服务实现
|
||||
|
||||
### 2.1 服务端实现
|
||||
```java
|
||||
// BookManagerService.java
|
||||
public class BookManagerService extends Service {
|
||||
private static final String TAG = "BookManagerService";
|
||||
|
||||
// 线程安全的书籍列表
|
||||
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
|
||||
|
||||
// 监听器列表
|
||||
private CopyOnWriteArrayList<IBookListener> mListenerList =
|
||||
new CopyOnWriteArrayList<>();
|
||||
|
||||
// 死亡监听器
|
||||
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
// 客户端进程死亡处理
|
||||
Log.w(TAG, "binder died");
|
||||
}
|
||||
};
|
||||
|
||||
// Binder实现
|
||||
private Binder mBinder = new IBookManager.Stub() {
|
||||
@Override
|
||||
public int getBookCount() {
|
||||
return mBookList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Book getBook(int bookId) {
|
||||
for (Book book : mBookList) {
|
||||
if (book.getId() == bookId) {
|
||||
return book;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Book> getBookList() {
|
||||
return mBookList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBook(Book book) {
|
||||
mBookList.add(book);
|
||||
// 通知所有监听器
|
||||
for (IBookListener listener : mListenerList) {
|
||||
try {
|
||||
listener.onNewBookArrived(book);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerListener(IBookListener listener) {
|
||||
if (!mListenerList.contains(listener)) {
|
||||
mListenerList.add(listener);
|
||||
try {
|
||||
listener.asBinder().linkToDeath(mDeathRecipient, 0);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListener(IBookListener listener) {
|
||||
mListenerList.remove(listener);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
// 初始化数据
|
||||
mBookList.add(new Book(1, "Android开发艺术探索", 79.0));
|
||||
mBookList.add(new Book(2, "深入理解Android内核设计", 89.0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 客户端调用
|
||||
```java
|
||||
// MainActivity.java
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
private IBookManager mBookManager;
|
||||
private ServiceConnection mConnection = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
mBookManager = IBookManager.Stub.asInterface(service);
|
||||
try {
|
||||
// 连接死亡监听
|
||||
service.linkToDeath(mDeathRecipient, 0);
|
||||
|
||||
// 调用远程方法
|
||||
int count = mBookManager.getBookCount();
|
||||
Log.d(TAG, "Book count: " + count);
|
||||
|
||||
// 获取书籍列表
|
||||
List<Book> bookList = mBookManager.getBookList();
|
||||
for (Book book : bookList) {
|
||||
Log.d(TAG, "Book: " + book.getName());
|
||||
}
|
||||
|
||||
// 注册监听器
|
||||
mBookManager.registerListener(mBookListener);
|
||||
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {
|
||||
mBookManager = null;
|
||||
}
|
||||
};
|
||||
|
||||
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
// 重新绑定服务
|
||||
if (mBookManager != null) {
|
||||
mBookManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
|
||||
mBookManager = null;
|
||||
}
|
||||
bindService();
|
||||
}
|
||||
};
|
||||
|
||||
private IBookListener mBookListener = new IBookListener.Stub() {
|
||||
@Override
|
||||
public void onNewBookArrived(Book newBook) {
|
||||
// 注意:这里运行在Binder线程池中
|
||||
runOnUiThread(() -> {
|
||||
Toast.makeText(MainActivity.this,
|
||||
"New book: " + newBook.getName(),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
private void bindService() {
|
||||
Intent intent = new Intent(this, BookManagerService.class);
|
||||
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_main);
|
||||
bindService();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
if (mBookManager != null && mBookManager.asBinder().isBinderAlive()) {
|
||||
try {
|
||||
mBookManager.unregisterListener(mBookListener);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
unbindService(mConnection);
|
||||
super.onDestroy();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. HIDL基础
|
||||
|
||||
### 3.1 HIDL接口定义
|
||||
```java
|
||||
// IExample.hal
|
||||
package android.hardware.example@1.0;
|
||||
|
||||
interface IExample {
|
||||
// 同步方法
|
||||
getVersion() generates (uint32_t major, uint32_t minor);
|
||||
|
||||
// 异步方法
|
||||
setValue(uint32_t value);
|
||||
|
||||
// 带返回值的异步方法
|
||||
getValue() generates (uint32_t value);
|
||||
|
||||
// 回调接口
|
||||
registerCallback(IExampleCallback callback);
|
||||
|
||||
// 复杂数据类型
|
||||
struct Data {
|
||||
vec<uint8_t> bytes;
|
||||
string name;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
processData(Data data) generates (Data result);
|
||||
};
|
||||
```
|
||||
|
||||
### 3.2 HIDL服务实现
|
||||
```cpp
|
||||
// Example.cpp - HAL实现
|
||||
#include <android/hardware/example/1.0/IExample.h>
|
||||
#include <hidl/LegacySupport.h>
|
||||
#include <hidl/HidlSupport.h>
|
||||
|
||||
using android::hardware::example::V1_0::IExample;
|
||||
using android::hardware::example::V1_0::IExampleCallback;
|
||||
using android::hardware::example::V1_0::Data;
|
||||
using android::hardware::Return;
|
||||
using android::hardware::Void;
|
||||
using android::hardware::hidl_vec;
|
||||
using android::hardware::hidl_string;
|
||||
using android::sp;
|
||||
|
||||
class ExampleImpl : public IExample {
|
||||
private:
|
||||
uint32_t mValue;
|
||||
sp<IExampleCallback> mCallback;
|
||||
|
||||
public:
|
||||
ExampleImpl() : mValue(0) {}
|
||||
|
||||
// 获取版本信息
|
||||
Return<void> getVersion(getVersion_cb _hidl_cb) override {
|
||||
_hidl_cb(1, 0); // 返回主版本和次版本
|
||||
return Void();
|
||||
}
|
||||
|
||||
// 设置值
|
||||
Return<void> setValue(uint32_t value) override {
|
||||
mValue = value;
|
||||
|
||||
// 通知回调
|
||||
if (mCallback != nullptr) {
|
||||
mCallback->onValueChanged(value);
|
||||
}
|
||||
|
||||
return Void();
|
||||
}
|
||||
|
||||
// 获取值
|
||||
Return<void> getValue(getValue_cb _hidl_cb) override {
|
||||
_hidl_cb(mValue);
|
||||
return Void();
|
||||
}
|
||||
|
||||
// 注册回调
|
||||
Return<void> registerCallback(const sp<IExampleCallback>& callback) override {
|
||||
mCallback = callback;
|
||||
return Void();
|
||||
}
|
||||
|
||||
// 处理数据
|
||||
Return<void> processData(const Data& input, processData_cb _hidl_cb) override {
|
||||
Data result;
|
||||
result.id = input.id + 1;
|
||||
result.name = "processed_" + input.name;
|
||||
|
||||
// 处理字节数据
|
||||
result.bytes.resize(input.bytes.size());
|
||||
for (size_t i = 0; i < input.bytes.size(); i++) {
|
||||
result.bytes[i] = input.bytes[i] ^ 0xFF; // 简单加密
|
||||
}
|
||||
|
||||
_hidl_cb(result);
|
||||
return Void();
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
android::sp<IExample> service = new ExampleImpl();
|
||||
return service->registerAsService();
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 性能优化与最佳实践
|
||||
|
||||
### 4.1 AIDL性能优化
|
||||
```java
|
||||
// 批量数据传输优化
|
||||
class BatchDataTransfer {
|
||||
// 不好的做法:多次跨进程调用
|
||||
public void transferDataPoor(List<Data> dataList) {
|
||||
for (Data data : dataList) {
|
||||
mAidlService.processData(data); // 每次都是跨进程调用
|
||||
}
|
||||
}
|
||||
|
||||
// 好的做法:批量传输
|
||||
public void transferDataGood(List<Data> dataList) {
|
||||
mAidlService.processBatchData(dataList); // 一次跨进程调用
|
||||
}
|
||||
}
|
||||
|
||||
// 使用ParcelFileDescriptor传输大文件
|
||||
public void transferLargeFile(File file) throws IOException {
|
||||
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
|
||||
file, ParcelFileDescriptor.MODE_READ_ONLY);
|
||||
mAidlService.processLargeFile(pfd);
|
||||
pfd.close();
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 线程安全处理
|
||||
```java
|
||||
// 线程安全的AIDL服务
|
||||
class ThreadSafeAidlService extends Service {
|
||||
private final Object mLock = new Object();
|
||||
private Map<String, Data> mDataMap = new HashMap<>();
|
||||
|
||||
private final IAidlService.Stub mBinder = new IAidlService.Stub() {
|
||||
@Override
|
||||
public Data getData(String key) {
|
||||
synchronized (mLock) {
|
||||
return mDataMap.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setData(String key, Data data) {
|
||||
synchronized (mLock) {
|
||||
mDataMap.put(key, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Data> getAllData() {
|
||||
synchronized (mLock) {
|
||||
return new ArrayList<>(mDataMap.values());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 错误处理与重试
|
||||
```java
|
||||
// 健壮的AIDL客户端
|
||||
class RobustAidlClient {
|
||||
private IAidlService mService;
|
||||
private static final int MAX_RETRY_COUNT = 3;
|
||||
|
||||
public Data getDataWithRetry(String key) {
|
||||
int retryCount = 0;
|
||||
while (retryCount < MAX_RETRY_COUNT) {
|
||||
try {
|
||||
if (mService == null || !mService.asBinder().isBinderAlive()) {
|
||||
reconnectService();
|
||||
}
|
||||
return mService.getData(key);
|
||||
} catch (RemoteException e) {
|
||||
retryCount++;
|
||||
if (retryCount >= MAX_RETRY_COUNT) {
|
||||
throw new RuntimeException("Failed to get data after retries", e);
|
||||
}
|
||||
// 等待后重试
|
||||
try {
|
||||
Thread.sleep(100 * retryCount);
|
||||
} catch (InterruptedException ie) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Interrupted during retry", ie);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void reconnectService() {
|
||||
// 重新绑定服务逻辑
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 调试与问题排查
|
||||
|
||||
### 5.1 AIDL调试工具
|
||||
```bash
|
||||
# 查看Binder状态
|
||||
adb shell dumpsys activity services
|
||||
adb shell dumpsys activity processes | grep -A 30 "Binder"
|
||||
|
||||
# 查看服务连接
|
||||
adb shell dumpsys activity top | grep -A 20 "ServiceConnection"
|
||||
|
||||
# 性能分析
|
||||
adb shell am trace-ipc start
|
||||
# ...执行操作...
|
||||
adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
|
||||
```
|
||||
|
||||
### 5.2 常见问题与解决方案
|
||||
- **Binder传输限制**:单个Binder事务大小限制为1MB,大文件使用ParcelFileDescriptor
|
||||
- **内存泄漏**:及时注销监听器,避免持有服务引用导致内存泄漏
|
||||
- **线程安全问题**:AIDL方法运行在Binder线程池,注意线程同步
|
||||
- **服务死亡处理**:实现DeathRecipient监听,服务死亡时重新绑定
|
||||
- **版本兼容性**:AIDL接口变更时注意向后兼容,HIDL使用主版本号管理兼容性
|
||||
|
||||
### 5.3 性能监控
|
||||
```java
|
||||
// AIDL调用性能监控
|
||||
class AidlPerformanceMonitor {
|
||||
private Map<String, CallStats> mCallStats = new ConcurrentHashMap<>();
|
||||
|
||||
class CallStats {
|
||||
long callCount;
|
||||
long totalTime;
|
||||
long maxTime;
|
||||
|
||||
synchronized void recordCall(long duration) {
|
||||
callCount++;
|
||||
totalTime += duration;
|
||||
maxTime = Math.max(maxTime, duration);
|
||||
}
|
||||
}
|
||||
|
||||
public <T> T monitorCall(String methodName, Supplier<T> task) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
return task.get();
|
||||
} finally {
|
||||
long endTime = System.currentTimeMillis();
|
||||
long duration = endTime - startTime;
|
||||
|
||||
CallStats stats = mCallStats.computeIfAbsent(
|
||||
methodName, k -> new CallStats());
|
||||
stats.recordCall(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
AIDL和HIDL是Android系统中重要的跨进程通信机制,理解它们的原理和最佳实践对于开发高性能、稳定的Android应用至关重要。通过合理的接口设计、线程安全处理和错误恢复机制,可以构建出健壮的跨进程通信架构。
|
||||
|
||||
@@ -1 +1,79 @@
|
||||
# Binder机制(内核到Java层)
|
||||
|
||||
Binder是Android系统中最重要的跨进程通信(IPC)机制,贯穿整个Android系统架构。本文从内核层到Java层深入分析Binder的工作原理、实现机制和优化策略。
|
||||
|
||||
## Binder架构全景
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "应用层"
|
||||
A1[客户端应用] --> A2[Binder代理]
|
||||
A3[服务端应用] --> A4[Binder Stub]
|
||||
end
|
||||
|
||||
subgraph "Framework层"
|
||||
B1[Binder驱动] --> B2[ServiceManager]
|
||||
B2 --> B3[系统服务]
|
||||
B3 --> B4[应用服务]
|
||||
end
|
||||
|
||||
subgraph "内核层"
|
||||
C1[Binder驱动] --> C2[内存映射]
|
||||
C2 --> C3[进程间通信]
|
||||
C3 --> C4[线程管理]
|
||||
end
|
||||
|
||||
subgraph "数据传输"
|
||||
D1[Parcel序列化] --> D2[Binder事务]
|
||||
D2 --> D3[内存共享]
|
||||
D3 --> D4[数据拷贝]
|
||||
end
|
||||
```
|
||||
|
||||
## 1. Binder内核层实现
|
||||
|
||||
### 1.1 Binder驱动核心数据结构
|
||||
Binder驱动在内核层维护了进程、线程、事务等核心数据结构,通过红黑树高效管理Binder实体和引用。
|
||||
|
||||
### 1.2 Binder内存映射机制
|
||||
Binder通过内存映射实现零拷贝数据传输,每个Binder进程映射一块共享内存区域,用于高效的数据传输。
|
||||
|
||||
### 1.3 Binder事务处理
|
||||
Binder事务处理包括事务创建、目标查找、数据传递和线程唤醒等步骤,支持同步和异步两种通信模式。
|
||||
|
||||
## 2. Framework层Binder实现
|
||||
|
||||
### 2.1 Java层Binder接口
|
||||
IBinder接口定义了Binder通信的基本操作,包括事务传输、死亡通知、接口查询等功能。
|
||||
|
||||
### 2.2 Binder代理与Stub实现
|
||||
Binder类实现了IBinder接口,提供了本地事务处理和跨进程通信的基础框架。
|
||||
|
||||
### 2.3 ServiceManager实现
|
||||
ServiceManager是系统服务的注册中心,管理所有系统服务的Binder引用。
|
||||
|
||||
## 3. Binder性能优化
|
||||
|
||||
### 3.1 内存优化策略
|
||||
使用Parcel对象池和线程本地Parcel,减少对象创建和垃圾回收开销。
|
||||
|
||||
### 3.2 事务优化
|
||||
支持批量事务处理,减少跨进程调用次数,提高数据传输效率。
|
||||
|
||||
### 3.3 异步Binder调用
|
||||
通过线程池和CompletableFuture实现异步Binder调用,避免阻塞主线程。
|
||||
|
||||
## 4. Binder调试与问题排查
|
||||
|
||||
### 4.1 Binder调试工具
|
||||
使用adb命令和内核调试接口查看Binder状态和事务信息。
|
||||
|
||||
### 4.2 常见问题与解决方案
|
||||
处理Binder事务失败、内存泄漏、线程阻塞等常见问题。
|
||||
|
||||
### 4.3 性能监控
|
||||
实现Binder调用性能监控,统计调用次数、耗时和错误率。
|
||||
|
||||
## 5. 总结
|
||||
|
||||
Binder作为Android系统的核心IPC机制,其设计体现了高效、安全、可扩展的特点。理解Binder的工作原理对于Android系统开发、性能优化和问题排查都具有重要意义。
|
||||
|
||||
@@ -1 +1,90 @@
|
||||
# Handler机制源码解析
|
||||
|
||||
Handler是Android系统中实现线程间通信的核心机制,广泛应用于UI更新、异步任务处理等场景。本文深入分析Handler、Looper、MessageQueue的源码实现和工作原理。
|
||||
|
||||
## Handler机制架构
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "核心组件"
|
||||
A1[Handler] --> A2[Message]
|
||||
A2 --> A3[MessageQueue]
|
||||
A3 --> A4[Looper]
|
||||
A4 --> A5[ThreadLocal]
|
||||
end
|
||||
|
||||
subgraph "工作流程"
|
||||
B1[发送消息] --> B2[消息入队]
|
||||
B2 --> B3[消息循环]
|
||||
B3 --> B4[消息分发]
|
||||
B4 --> B5[消息处理]
|
||||
end
|
||||
|
||||
subgraph "线程模型"
|
||||
C1[主线程] --> C2[UI线程]
|
||||
C3[工作线程] --> C4[后台线程]
|
||||
C5[Binder线程] --> C6[IPC线程]
|
||||
end
|
||||
|
||||
subgraph "优化策略"
|
||||
D1[消息复用] --> D2[异步屏障]
|
||||
D3[空闲处理] --> D4[同步屏障]
|
||||
D5[延迟消息] --> D6[即时消息]
|
||||
end
|
||||
```
|
||||
|
||||
## 1. Handler核心组件源码分析
|
||||
|
||||
### 1.1 Handler类源码
|
||||
Handler是消息的发送者和处理者,负责将消息发送到消息队列,并在适当的时候处理消息。
|
||||
|
||||
### 1.2 Message类源码
|
||||
Message是消息的载体,包含消息标识、参数和数据,支持对象池复用机制。
|
||||
|
||||
### 1.3 Looper类源码
|
||||
Looper是消息循环的核心,每个线程只能有一个Looper,负责从消息队列中取出消息并分发给Handler处理。
|
||||
|
||||
### 1.4 MessageQueue类源码
|
||||
MessageQueue是消息队列,使用链表结构存储消息,支持延迟消息和同步屏障等高级特性。
|
||||
|
||||
## 2. Handler工作机制深入分析
|
||||
|
||||
### 2.1 消息发送流程
|
||||
消息发送包括创建消息、设置参数、入队等步骤,支持立即发送、延迟发送和插入队头等多种方式。
|
||||
|
||||
### 2.2 消息处理流程
|
||||
消息处理遵循优先级:Runnable回调 > Handler.Callback > handleMessage()方法。
|
||||
|
||||
## 3. Handler高级特性
|
||||
|
||||
### 3.1 同步屏障机制
|
||||
同步屏障用于优先处理异步消息,适用于需要立即响应的场景。
|
||||
|
||||
### 3.2 空闲处理器
|
||||
空闲处理器在消息队列空闲时执行,适用于低优先级任务。
|
||||
|
||||
## 4. Handler性能优化与最佳实践
|
||||
|
||||
### 4.1 消息复用优化
|
||||
使用Message.obtain()获取消息对象,避免频繁创建和GC压力。
|
||||
|
||||
### 4.2 避免内存泄漏
|
||||
使用静态内部类+弱引用,及时移除消息和回调。
|
||||
|
||||
### 4.3 线程安全处理
|
||||
确保多线程环境下Handler的正确使用和同步。
|
||||
|
||||
## 5. Handler调试与问题排查
|
||||
|
||||
### 5.1 Handler调试工具
|
||||
使用adb命令和系统工具查看Handler状态和消息队列。
|
||||
|
||||
### 5.2 常见问题与解决方案
|
||||
处理内存泄漏、ANR、消息丢失等常见问题。
|
||||
|
||||
### 5.3 性能监控
|
||||
实现Handler性能监控,统计消息处理时间和延迟情况。
|
||||
|
||||
## 6. 总结
|
||||
|
||||
Handler机制是Android系统线程间通信的核心,理解其源码实现对于开发高性能、稳定的Android应用至关重要。
|
||||
|
||||
@@ -1 +1,151 @@
|
||||
# 05-进程与线程通信
|
||||
# 05-进程与线程通信
|
||||
|
||||
本目录包含Android系统中进程与线程通信相关技术的深入分析和源码解析。涵盖了Binder机制、Handler机制、AIDL/HIDL、跨进程同步等核心内容。
|
||||
|
||||
## 文件结构
|
||||
|
||||
### 核心文档
|
||||
1. **跨进程同步与锁优化.md** - 深入分析Android跨进程同步机制、锁优化策略和最佳实践
|
||||
2. **AIDL与HIDL使用与原理.md** - 详细解析AIDL和HIDL的接口定义、服务实现和性能优化
|
||||
3. **Binder机制(内核到Java层).md** - 从内核层到Java层全面分析Binder的工作原理和实现机制
|
||||
4. **Handler机制源码解析.md** - 深入分析Handler、Looper、MessageQueue的源码实现和工作原理
|
||||
|
||||
### 技术要点
|
||||
|
||||
#### 1. 跨进程同步与锁优化
|
||||
- 进程同步原语分类(Mutex、RWLock、Condition等)
|
||||
- 跨进程同步机制(文件锁、共享内存、Binder同步)
|
||||
- 锁优化策略(锁粒度优化、锁竞争避免、死锁预防)
|
||||
- 性能监控与自适应锁优化
|
||||
|
||||
#### 2. AIDL与HIDL使用与原理
|
||||
- AIDL接口定义和Parcelable对象实现
|
||||
- AIDL服务端和客户端实现
|
||||
- HIDL接口定义和HAL层实现
|
||||
- 性能优化和最佳实践
|
||||
|
||||
#### 3. Binder机制(内核到Java层)
|
||||
- Binder驱动核心数据结构和内存映射机制
|
||||
- Binder事务处理流程
|
||||
- Framework层Binder接口和ServiceManager实现
|
||||
- Binder性能优化策略
|
||||
|
||||
#### 4. Handler机制源码解析
|
||||
- Handler、Message、Looper、MessageQueue源码分析
|
||||
- 消息发送和处理流程
|
||||
- 同步屏障和空闲处理器高级特性
|
||||
- Handler性能优化和内存泄漏预防
|
||||
|
||||
## 学习路径
|
||||
|
||||
### 初级(了解基础概念)
|
||||
1. 阅读Handler机制源码解析.md,理解Android线程通信基础
|
||||
2. 学习跨进程同步与锁优化.md中的同步原语部分
|
||||
|
||||
### 中级(掌握核心机制)
|
||||
1. 深入学习Binder机制(内核到Java层).md,理解Android IPC核心
|
||||
2. 学习AIDL与HIDL使用与原理.md,掌握接口定义和服务实现
|
||||
|
||||
### 高级(优化和问题排查)
|
||||
1. 研究各文档中的性能优化部分
|
||||
2. 学习调试工具和问题排查方法
|
||||
3. 实践高级特性如同步屏障、空闲处理器等
|
||||
|
||||
## 调试工具
|
||||
|
||||
### Binder调试
|
||||
```bash
|
||||
# 查看Binder状态
|
||||
adb shell dumpsys activity services
|
||||
adb shell cat /sys/kernel/debug/binder/state
|
||||
|
||||
# Binder性能分析
|
||||
adb shell am trace-ipc start
|
||||
adb shell am trace-ipc stop --dump-file /data/local/tmp/ipc-trace.txt
|
||||
```
|
||||
|
||||
### Handler调试
|
||||
```bash
|
||||
# 查看主线程消息队列
|
||||
adb shell dumpsys activity processes | grep -A 50 "main"
|
||||
|
||||
# Handler消息统计
|
||||
adb shell dumpsys activity top | grep -A 20 "Handler"
|
||||
```
|
||||
|
||||
### 性能分析工具
|
||||
- Systrace/Perfetto:分析系统性能
|
||||
- Android Profiler:分析内存和CPU使用
|
||||
- Traceview:方法调用跟踪
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 1. 内存泄漏问题
|
||||
- Handler内存泄漏:使用静态内部类+弱引用
|
||||
- Binder服务泄漏:及时注销DeathRecipient
|
||||
- 消息未回收:及时调用Message.recycle()
|
||||
|
||||
### 2. 性能问题
|
||||
- ANR问题:避免在主线程执行耗时操作
|
||||
- 锁竞争:优化锁粒度,使用读写锁
|
||||
- Binder调用频繁:使用批量事务
|
||||
|
||||
### 3. 线程安全问题
|
||||
- 多线程访问共享资源:使用合适的同步机制
|
||||
- Handler跨线程使用:确保线程安全
|
||||
- Binder回调线程:注意回调线程环境
|
||||
|
||||
## 最佳实践
|
||||
|
||||
### 代码规范
|
||||
1. 使用Message.obtain()获取消息对象,避免频繁创建
|
||||
2. 及时回收消息和清理资源
|
||||
3. 使用合适的同步机制,避免死锁
|
||||
4. 合理设计接口,减少跨进程调用次数
|
||||
|
||||
### 性能优化
|
||||
1. 复用对象,减少GC压力
|
||||
2. 使用异步调用,避免阻塞主线程
|
||||
3. 合理设置消息优先级
|
||||
4. 监控性能指标,及时优化
|
||||
|
||||
### 调试技巧
|
||||
1. 使用系统工具分析问题
|
||||
2. 添加日志和监控代码
|
||||
3. 使用单元测试验证功能
|
||||
4. 性能测试和压力测试
|
||||
|
||||
## 扩展阅读
|
||||
|
||||
### 官方文档
|
||||
- [Android Interface Definition Language (AIDL)](https://developer.android.com/guide/components/aidl)
|
||||
- [Handlers and Loopers](https://developer.android.com/reference/android/os/Handler)
|
||||
- [Binder IPC](https://source.android.com/docs/core/architecture/hidl/binder-ipc)
|
||||
|
||||
### 源码位置
|
||||
- Framework层:`frameworks/base/core/java/android/os/`
|
||||
- 内核层:`kernel/drivers/android/binder.c`
|
||||
- AIDL生成代码:`build/generated/aidl_source_output_dir/`
|
||||
|
||||
### 相关技术
|
||||
- ServiceManager:系统服务管理
|
||||
- Parcel:数据序列化
|
||||
- ThreadLocal:线程本地存储
|
||||
- 同步原语:Mutex、Condition、Semaphore等
|
||||
|
||||
## 更新日志
|
||||
|
||||
### 2026-01-12
|
||||
- 完善所有核心文档内容
|
||||
- 添加详细的技术分析和代码示例
|
||||
- 补充性能优化和最佳实践
|
||||
- 添加调试工具和问题排查方法
|
||||
|
||||
### 2026-01-05
|
||||
- 创建目录结构
|
||||
- 初始化文档框架
|
||||
- 添加基础内容
|
||||
|
||||
---
|
||||
|
||||
**注意**:本文档内容基于Android开源项目源码分析,适用于Android系统开发者和Framework开发者。建议结合源码阅读和实践使用。
|
||||
|
||||
@@ -1 +1,571 @@
|
||||
# 跨进程同步与锁优化
|
||||
|
||||
在Android多进程架构中,进程间同步和锁机制是保证数据一致性和系统稳定性的关键技术。本文深入分析Android跨进程同步机制、锁优化策略和最佳实践。
|
||||
|
||||
## 进程同步架构概览
|
||||
|
||||
```mermaid
|
||||
graph TB
|
||||
subgraph "同步原语"
|
||||
A1[互斥锁 Mutex] --> A2[条件变量 Condition]
|
||||
A2 --> A3[读写锁 RWLock]
|
||||
A3 --> A4[信号量 Semaphore]
|
||||
A4 --> A5[屏障 Barrier]
|
||||
end
|
||||
|
||||
subgraph "跨进程同步"
|
||||
B1[文件锁] --> B2[共享内存]
|
||||
B2 --> B3[消息队列]
|
||||
B3 --> B4[信号量]
|
||||
B4 --> B5[Binder同步]
|
||||
end
|
||||
|
||||
subgraph "优化策略"
|
||||
C1[锁粒度优化] --> C2[锁竞争避免]
|
||||
C2 --> C3[死锁预防]
|
||||
C3 --> C4[性能监控]
|
||||
C4 --> C5[自适应锁]
|
||||
end
|
||||
```
|
||||
|
||||
## 1. 进程同步基础
|
||||
|
||||
### 1.1 同步原语分类
|
||||
- **互斥锁(Mutex)**:保证同一时间只有一个线程访问共享资源
|
||||
- **读写锁(RWLock)**:允许多个读线程同时访问,写线程独占访问
|
||||
- **条件变量(Condition)**:线程等待特定条件满足
|
||||
- **信号量(Semaphore)**:控制同时访问资源的线程数量
|
||||
- **屏障(Barrier)**:等待多个线程到达同步点
|
||||
|
||||
### 1.2 Android中的同步机制
|
||||
```cpp
|
||||
// Android中的同步原语实现
|
||||
class AndroidSync {
|
||||
// 1. Mutex实现
|
||||
class Mutex {
|
||||
private:
|
||||
pthread_mutex_t mMutex;
|
||||
public:
|
||||
Mutex() { pthread_mutex_init(&mMutex, NULL); }
|
||||
~Mutex() { pthread_mutex_destroy(&mMutex); }
|
||||
void lock() { pthread_mutex_lock(&mMutex); }
|
||||
void unlock() { pthread_mutex_unlock(&mMutex); }
|
||||
};
|
||||
|
||||
// 2. Condition实现
|
||||
class Condition {
|
||||
private:
|
||||
pthread_cond_t mCond;
|
||||
Mutex& mMutex;
|
||||
public:
|
||||
Condition(Mutex& mutex) : mMutex(mutex) {
|
||||
pthread_cond_init(&mCond, NULL);
|
||||
}
|
||||
void wait() { pthread_cond_wait(&mCond, &mMutex.mMutex); }
|
||||
void signal() { pthread_cond_signal(&mCond); }
|
||||
void broadcast() { pthread_cond_broadcast(&mCond); }
|
||||
};
|
||||
|
||||
// 3. 读写锁实现
|
||||
class RWLock {
|
||||
private:
|
||||
pthread_rwlock_t mLock;
|
||||
public:
|
||||
RWLock() { pthread_rwlock_init(&mLock, NULL); }
|
||||
~RWLock() { pthread_rwlock_destroy(&mLock); }
|
||||
void readLock() { pthread_rwlock_rdlock(&mLock); }
|
||||
void writeLock() { pthread_rwlock_wrlock(&mLock); }
|
||||
void unlock() { pthread_rwlock_unlock(&mLock); }
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
## 2. 跨进程同步机制
|
||||
|
||||
### 2.1 文件锁(File Lock)
|
||||
```cpp
|
||||
// 文件锁实现跨进程同步
|
||||
class FileLock {
|
||||
private:
|
||||
int mFd;
|
||||
struct flock mLock;
|
||||
|
||||
public:
|
||||
FileLock(const char* filename) {
|
||||
// 打开文件
|
||||
mFd = open(filename, O_RDWR | O_CREAT, 0644);
|
||||
if (mFd < 0) {
|
||||
perror("open file failed");
|
||||
}
|
||||
}
|
||||
|
||||
~FileLock() {
|
||||
if (mFd >= 0) {
|
||||
close(mFd);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取排他锁
|
||||
bool lockExclusive() {
|
||||
mLock.l_type = F_WRLCK; // 写锁(排他锁)
|
||||
mLock.l_whence = SEEK_SET;
|
||||
mLock.l_start = 0;
|
||||
mLock.l_len = 0; // 锁定整个文件
|
||||
|
||||
return fcntl(mFd, F_SETLKW, &mLock) != -1;
|
||||
}
|
||||
|
||||
// 获取共享锁
|
||||
bool lockShared() {
|
||||
mLock.l_type = F_RDLCK; // 读锁(共享锁)
|
||||
mLock.l_whence = SEEK_SET;
|
||||
mLock.l_start = 0;
|
||||
mLock.l_len = 0;
|
||||
|
||||
return fcntl(mFd, F_SETLKW, &mLock) != -1;
|
||||
}
|
||||
|
||||
// 释放锁
|
||||
bool unlock() {
|
||||
mLock.l_type = F_UNLCK;
|
||||
return fcntl(mFd, F_SETLK, &mLock) != -1;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 共享内存同步
|
||||
```cpp
|
||||
// 共享内存+信号量实现跨进程同步
|
||||
class SharedMemorySync {
|
||||
private:
|
||||
int mShmId;
|
||||
void* mShmAddr;
|
||||
sem_t* mSemaphore;
|
||||
|
||||
public:
|
||||
SharedMemorySync(const char* key, size_t size) {
|
||||
// 1. 创建共享内存
|
||||
key_t shmKey = ftok(key, 'R');
|
||||
mShmId = shmget(shmKey, size, 0644 | IPC_CREAT);
|
||||
|
||||
// 2. 附加到进程地址空间
|
||||
mShmAddr = shmat(mShmId, NULL, 0);
|
||||
|
||||
// 3. 创建信号量
|
||||
mSemaphore = sem_open(key, O_CREAT, 0644, 1);
|
||||
}
|
||||
|
||||
~SharedMemorySync() {
|
||||
// 分离共享内存
|
||||
shmdt(mShmAddr);
|
||||
// 关闭信号量
|
||||
sem_close(mSemaphore);
|
||||
}
|
||||
|
||||
// 进入临界区
|
||||
void enterCriticalSection() {
|
||||
sem_wait(mSemaphore); // P操作
|
||||
}
|
||||
|
||||
// 离开临界区
|
||||
void leaveCriticalSection() {
|
||||
sem_post(mSemaphore); // V操作
|
||||
}
|
||||
|
||||
// 获取共享内存地址
|
||||
void* getSharedMemory() {
|
||||
return mShmAddr;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 2.3 Binder同步机制
|
||||
```java
|
||||
// Binder跨进程同步示例
|
||||
public class BinderSyncService extends Service {
|
||||
private final Object mLock = new Object();
|
||||
private int mSharedValue = 0;
|
||||
|
||||
private final IBinder mBinder = new ISyncService.Stub() {
|
||||
@Override
|
||||
public synchronized int getValue() {
|
||||
synchronized (mLock) {
|
||||
// 跨进程同步访问
|
||||
return mSharedValue;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void setValue(int value) {
|
||||
synchronized (mLock) {
|
||||
// 跨进程同步修改
|
||||
mSharedValue = value;
|
||||
// 通知等待的线程
|
||||
mLock.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void waitForValue(int target) throws RemoteException {
|
||||
synchronized (mLock) {
|
||||
while (mSharedValue != target) {
|
||||
try {
|
||||
// 跨进程等待
|
||||
mLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return mBinder;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 锁优化策略
|
||||
|
||||
### 3.1 锁粒度优化
|
||||
```java
|
||||
// 锁粒度优化示例
|
||||
class LockGranularityOptimization {
|
||||
// 粗粒度锁 - 性能较差
|
||||
private final Object mCoarseLock = new Object();
|
||||
private Map<String, Integer> mData1 = new HashMap<>();
|
||||
private Map<String, String> mData2 = new HashMap<>();
|
||||
|
||||
public void updateCoarse(String key, int value, String str) {
|
||||
synchronized (mCoarseLock) { // 锁住所有数据
|
||||
mData1.put(key, value);
|
||||
mData2.put(key, str);
|
||||
}
|
||||
}
|
||||
|
||||
// 细粒度锁 - 性能更好
|
||||
private final Object mLock1 = new Object();
|
||||
private final Object mLock2 = new Object();
|
||||
|
||||
public void updateFine(String key, int value, String str) {
|
||||
synchronized (mLock1) { // 只锁住相关数据
|
||||
mData1.put(key, value);
|
||||
}
|
||||
synchronized (mLock2) {
|
||||
mData2.put(key, str);
|
||||
}
|
||||
}
|
||||
|
||||
// 读写锁优化
|
||||
private final ReentrantReadWriteLock mRwLock = new ReentrantReadWriteLock();
|
||||
|
||||
public int readWithRWLock(String key) {
|
||||
mRwLock.readLock().lock();
|
||||
try {
|
||||
return mData1.getOrDefault(key, 0);
|
||||
} finally {
|
||||
mRwLock.readLock().unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeWithRWLock(String key, int value) {
|
||||
mRwLock.writeLock().lock();
|
||||
try {
|
||||
mData1.put(key, value);
|
||||
} finally {
|
||||
mRwLock.writeLock().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 锁竞争避免
|
||||
```java
|
||||
// 锁竞争避免策略
|
||||
class LockCompetitionAvoidance {
|
||||
// 1. 锁分解(Lock Splitting)
|
||||
private final Object[] mLocks;
|
||||
private final Map<String, String>[] mDataSegments;
|
||||
|
||||
public LockCompetitionAvoidance(int segments) {
|
||||
mLocks = new Object[segments];
|
||||
mDataSegments = new HashMap[segments];
|
||||
for (int i = 0; i < segments; i++) {
|
||||
mLocks[i] = new Object();
|
||||
mDataSegments[i] = new HashMap<>();
|
||||
}
|
||||
}
|
||||
|
||||
// 根据key哈希选择锁
|
||||
private int getSegmentIndex(String key) {
|
||||
return Math.abs(key.hashCode()) % mLocks.length;
|
||||
}
|
||||
|
||||
public void put(String key, String value) {
|
||||
int index = getSegmentIndex(key);
|
||||
synchronized (mLocks[index]) {
|
||||
mDataSegments[index].put(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 锁粗化(Lock Coarsening)
|
||||
public void lockCoarseningExample() {
|
||||
// 不好的做法:多次加锁解锁
|
||||
synchronized (this) {
|
||||
operation1();
|
||||
}
|
||||
synchronized (this) {
|
||||
operation2();
|
||||
}
|
||||
synchronized (this) {
|
||||
operation3();
|
||||
}
|
||||
|
||||
// 好的做法:锁粗化
|
||||
synchronized (this) {
|
||||
operation1();
|
||||
operation2();
|
||||
operation3();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 无锁编程(Lock-Free)
|
||||
private final AtomicInteger mAtomicCounter = new AtomicInteger(0);
|
||||
|
||||
public void lockFreeIncrement() {
|
||||
mAtomicCounter.incrementAndGet();
|
||||
}
|
||||
|
||||
private final ConcurrentHashMap<String, String> mConcurrentMap =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public void lockFreePut(String key, String value) {
|
||||
mConcurrentMap.put(key, value);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 死锁预防与检测
|
||||
```java
|
||||
// 死锁预防策略
|
||||
class DeadlockPrevention {
|
||||
// 1. 锁顺序一致
|
||||
private final Object mLockA = new Object();
|
||||
private final Object mLockB = new Object();
|
||||
|
||||
public void safeMethod1() {
|
||||
// 总是先获取lockA,再获取lockB
|
||||
synchronized (mLockA) {
|
||||
synchronized (mLockB) {
|
||||
// 操作共享资源
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void safeMethod2() {
|
||||
// 保持相同的锁顺序
|
||||
synchronized (mLockA) {
|
||||
synchronized (mLockB) {
|
||||
// 操作共享资源
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 锁超时机制
|
||||
public void lockWithTimeout() {
|
||||
ReentrantLock lock = new ReentrantLock();
|
||||
try {
|
||||
// 尝试获取锁,最多等待1秒
|
||||
if (lock.tryLock(1, TimeUnit.SECONDS)) {
|
||||
try {
|
||||
// 执行操作
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
} else {
|
||||
// 获取锁超时,执行备用方案
|
||||
handleLockTimeout();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 死锁检测
|
||||
public void deadlockDetection() {
|
||||
ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
|
||||
long[] threadIds = threadBean.findDeadlockedThreads();
|
||||
|
||||
if (threadIds != null) {
|
||||
ThreadInfo[] threadInfos = threadBean.getThreadInfo(threadIds);
|
||||
for (ThreadInfo threadInfo : threadInfos) {
|
||||
System.err.println("死锁检测到线程: " + threadInfo.getThreadName());
|
||||
System.err.println(" 等待锁: " + threadInfo.getLockName());
|
||||
System.err.println(" 被锁持有者: " + threadInfo.getLockOwnerName());
|
||||
}
|
||||
|
||||
// 死锁恢复策略
|
||||
recoverFromDeadlock(threadInfos);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleLockTimeout() {
|
||||
// 锁超时处理逻辑
|
||||
}
|
||||
|
||||
private void recoverFromDeadlock(ThreadInfo[] threadInfos) {
|
||||
// 死锁恢复逻辑,如中断线程、释放资源等
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. 性能监控与调优
|
||||
|
||||
### 4.1 锁性能监控
|
||||
```java
|
||||
// 锁性能监控工具
|
||||
class LockPerformanceMonitor {
|
||||
private final Map<String, LockStats> mLockStats = new ConcurrentHashMap<>();
|
||||
|
||||
class LockStats {
|
||||
long acquireCount;
|
||||
long totalWaitTime;
|
||||
long maxWaitTime;
|
||||
long contentionCount;
|
||||
|
||||
synchronized void recordAcquire(long waitTime) {
|
||||
acquireCount++;
|
||||
totalWaitTime += waitTime;
|
||||
maxWaitTime = Math.max(maxWaitTime, waitTime);
|
||||
if (waitTime > 10) { // 10ms视为竞争
|
||||
contentionCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 监控锁
|
||||
public <T> T monitorLock(String lockName, Supplier<T> task) {
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
return task.get();
|
||||
} finally {
|
||||
long endTime = System.currentTimeMillis();
|
||||
long waitTime = endTime - startTime;
|
||||
|
||||
LockStats stats = mLockStats.computeIfAbsent(
|
||||
lockName, k -> new LockStats());
|
||||
stats.recordAcquire(waitTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 生成性能报告
|
||||
public void generateReport() {
|
||||
for (Map.Entry<String, LockStats> entry : mLockStats.entrySet()) {
|
||||
LockStats stats = entry.getValue();
|
||||
if (stats.acquireCount > 0) {
|
||||
double avgWaitTime = (double) stats.totalWaitTime / stats.acquireCount;
|
||||
double contentionRate = (double) stats.contentionCount / stats.acquireCount;
|
||||
|
||||
System.out.println(String.format(
|
||||
"锁[%s]: 获取次数=%d, 平均等待=%.2fms, 最大等待=%dms, 竞争率=%.2f%%",
|
||||
entry.getKey(), stats.acquireCount, avgWaitTime,
|
||||
stats.maxWaitTime, contentionRate * 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 自适应锁优化
|
||||
```java
|
||||
// 自适应锁策略
|
||||
class AdaptiveLockStrategy {
|
||||
private final ReentrantLock mLock = new ReentrantLock();
|
||||
private volatile int mContentionLevel = 0;
|
||||
private volatile long mLastContentionTime = 0;
|
||||
|
||||
// 自适应获取锁
|
||||
public void adaptiveLock(Runnable task) {
|
||||
if (shouldUseSpinLock()) {
|
||||
// 使用自旋锁(低竞争场景)
|
||||
spinLock(task);
|
||||
} else {
|
||||
// 使用阻塞锁(高竞争场景)
|
||||
blockingLock(task);
|
||||
}
|
||||
|
||||
updateContentionLevel();
|
||||
}
|
||||
|
||||
private boolean shouldUseSpinLock() {
|
||||
long currentTime = System.currentTimeMillis();
|
||||
// 如果最近有竞争,使用阻塞锁
|
||||
if (currentTime - mLastContentionTime < 1000) {
|
||||
return false;
|
||||
}
|
||||
// 低竞争级别使用自旋锁
|
||||
return mContentionLevel < 3;
|
||||
}
|
||||
|
||||
private void spinLock(Runnable task) {
|
||||
int spinCount = 0;
|
||||
while (!mLock.tryLock()) {
|
||||
if (++spinCount > 100) {
|
||||
// 自旋次数过多,转为阻塞
|
||||
mLock.lock();
|
||||
break;
|
||||
}
|
||||
// 短暂自旋
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
mLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void blockingLock(Runnable task) {
|
||||
mLock.lock();
|
||||
try {
|
||||
task.run();
|
||||
} finally {
|
||||
mLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateContentionLevel() {
|
||||
// 根据锁竞争情况更新竞争级别
|
||||
if (mLock.hasQueuedThreads()) {
|
||||
mContentionLevel++;
|
||||
mLastContentionTime = System.currentTimeMillis();
|
||||
} else if (mContentionLevel > 0) {
|
||||
mContentionLevel--;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 调试与问题排查
|
||||
|
||||
### 5.1 锁问题调试工具
|
||||
```bash
|
||||
# 查看线程锁状态
|
||||
adb shell dumpsys activity processes | grep -A 20 "locked"
|
||||
adb shell ps -T | grep -E "(blocked|waiting)"
|
||||
|
||||
# 性能分析
|
||||
adb shell am dumpheap <pid> /data/local/tmp/heap.hprof
|
||||
adb shell am profile start <pid> /data/local/tmp/trace.trace
|
||||
|
||||
# systrace分析锁竞争
|
||||
python systrace.py --time=10 -o trace.html sched freq idle am wm gfx view sync
|
||||
```
|
||||
|
||||
### 5.2 常见问题与解决方案
|
||||
- **死锁问题**:使用锁顺序一致、锁超时机制、死锁检测工具
|
||||
- **锁竞争严重**:优化锁粒度、使用读写锁、减少锁持有时间
|
||||
- **性能瓶颈**:监控
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
curse 网站续费 https://cursor.com/cn/dashboard
|
||||
|
||||
|
||||
联通大王卡号:13022988679
|
||||
公司电信卡号:17392826953 QQ号:3145431252 密码:renjianbo0118 邮箱:3145431252@qq.com 密码:renjianbo0118 网易邮箱17392826953@163.com !renjianbo1219
|
||||
公司移动卡号:15129026818
|
||||
|
||||
|
||||
瑞来康健微信小程序账号:15129026818@163.com 密码:Ruilaizi123456
|
||||
公众号账号:17392826953@163.com 密码:Ruilaizi123456
|
||||
|
||||
|
||||
瑞来兹开票信息
|
||||
公司名称:西安瑞来兹软件科技有限公司
|
||||
统一社会信息代码:91610131MAB0GH1Y54
|
||||
地址:陕西省西安市高新区科技二路65号启迪科技园D座9楼10901号
|
||||
电话:18691577328
|
||||
开户行及帐号:中国农业银行股份有限公司西安丈八四路分理处
|
||||
26121201040005017
|
||||
|
||||
|
||||
|
||||
公司手机号:15129026818
|
||||
公司QQ号:2183824293 renjianbo0206 绑定的的手机18133922183
|
||||
微信小程序官网:https://mp.weixin.qq.com/
|
||||
小程序2183824293@qq.com renjianbo0118
|
||||
名片秘钥
|
||||
887cd30d79bba800b30d8c4ef919a20c
|
||||
公司服务器密码:~Ruilaizi123456
|
||||
|
||||
接口文档账号:903292507@qq.com renjianbo0118
|
||||
|
||||
项目管理系统
|
||||
https://pingcode.com/?utm_source=%E5%93%81%E7%89%8C%E4%B8%93%E5%8C%BA&utm_medium=pc-pingcode&utm_campaign=%E5%93%81%E7%89%8C%E4%B8%93%E5%8C%BA-%E9%AB%98%E7%BA%A7%E7%89%88&utm_content=PC-%E6%90%9C%E7%B4%A2%E9%80%9A%E6%A0%8F%E5%95%86%E5%93%81tab%E6%A0%B7%E5%BC%8F&utm_term=%E6%A0%87%E9%A2%98-PingCode&e_matchtype={matchtype}&e_creative={creative}&e_adposition={adposition}&e_pagenum={pagenum}&e_keywordid={keywordid}
|
||||
|
||||
管理 17392826953
|
||||
3145431252@qq.com renjianbo0118
|
||||
18302920526 ruilaizi
|
||||
18792702169 ruilaizi
|
||||
|
||||
|
||||
google账号:renj62507@gmail.com renjianbo123
|
||||
|
||||
|
||||
99API 账户:18133922183 renjianbo1219
|
||||
chatAI 18133922183@163.com !renjianbo0118
|
||||
|
||||
|
||||
儿童医院小程序注册邮箱 3669785689@qq.com !ruilaizi123456
|
||||
|
||||
微信开放平台 生长激素预测模型小程序 3990202197@qq.com renjianbo1219
|
||||
生长激素预测模型小程序3858752441@qq.com renjianbo1219
|
||||
飞书账号:15129026818
|
||||
github账号密码:263303411@qq.com renjianbo0118
|
||||
|
||||
硅基密钥:sk-xpptixobqxshkmikjvjeoltekytqmmresfndhoivezomuobn
|
||||
deepssk:sk-fdf7cc1c73504e628ec0119b7e11b8cc
|
||||
263303411 renjianbo1219
|
||||
|
||||
计算云 renjianbo 密码!Rjb1219
|
||||
|
||||
|
||||
荣耀开放平台 手机号 15129026818 邮箱263303411@qq.com renjianbo1219
|
||||
|
||||
|
||||
curse 网站续费 https://cursor.com/cn/dashboard
|
||||
curse 网站续费 https://cursor.com/cn/dashboard
|
||||
|
||||
|
||||
联通大王卡号:13022988679
|
||||
公司电信卡号:17392826953 QQ号:3145431252 密码:renjianbo0118 邮箱:3145431252@qq.com 密码:renjianbo0118 网易邮箱17392826953@163.com !renjianbo1219
|
||||
公司移动卡号:15129026818
|
||||
|
||||
|
||||
瑞来康健微信小程序账号:15129026818@163.com 密码:Ruilaizi123456
|
||||
公众号账号:17392826953@163.com 密码:Ruilaizi123456
|
||||
|
||||
|
||||
瑞来兹开票信息
|
||||
公司名称:西安瑞来兹软件科技有限公司
|
||||
统一社会信息代码:91610131MAB0GH1Y54
|
||||
地址:陕西省西安市高新区科技二路65号启迪科技园D座9楼10901号
|
||||
电话:18691577328
|
||||
开户行及帐号:中国农业银行股份有限公司西安丈八四路分理处
|
||||
26121201040005017
|
||||
|
||||
|
||||
|
||||
公司手机号:15129026818
|
||||
公司QQ号:2183824293 renjianbo0206 绑定的的手机18133922183
|
||||
微信小程序官网:https://mp.weixin.qq.com/
|
||||
小程序2183824293@qq.com renjianbo0118
|
||||
名片秘钥
|
||||
887cd30d79bba800b30d8c4ef919a20c
|
||||
公司服务器密码:~Ruilaizi123456
|
||||
|
||||
接口文档账号:903292507@qq.com renjianbo0118
|
||||
|
||||
项目管理系统
|
||||
https://pingcode.com/?utm_source=%E5%93%81%E7%89%8C%E4%B8%93%E5%8C%BA&utm_medium=pc-pingcode&utm_campaign=%E5%93%81%E7%89%8C%E4%B8%93%E5%8C%BA-%E9%AB%98%E7%BA%A7%E7%89%88&utm_content=PC-%E6%90%9C%E7%B4%A2%E9%80%9A%E6%A0%8F%E5%95%86%E5%93%81tab%E6%A0%B7%E5%BC%8F&utm_term=%E6%A0%87%E9%A2%98-PingCode&e_matchtype={matchtype}&e_creative={creative}&e_adposition={adposition}&e_pagenum={pagenum}&e_keywordid={keywordid}
|
||||
|
||||
管理 17392826953
|
||||
3145431252@qq.com renjianbo0118
|
||||
18302920526 ruilaizi
|
||||
18792702169 ruilaizi
|
||||
|
||||
|
||||
google账号:renj62507@gmail.com renjianbo123
|
||||
|
||||
|
||||
99API 账户:18133922183 renjianbo1219
|
||||
chatAI 18133922183@163.com !renjianbo0118
|
||||
|
||||
|
||||
儿童医院小程序注册邮箱 3669785689@qq.com !ruilaizi123456
|
||||
|
||||
微信开放平台 生长激素预测模型小程序 3990202197@qq.com renjianbo1219
|
||||
生长激素预测模型小程序3858752441@qq.com renjianbo1219
|
||||
飞书账号:15129026818
|
||||
github账号密码:263303411@qq.com renjianbo0118
|
||||
|
||||
硅基密钥:sk-xpptixobqxshkmikjvjeoltekytqmmresfndhoivezomuobn
|
||||
deepssk:sk-fdf7cc1c73504e628ec0119b7e11b8cc
|
||||
263303411 renjianbo1219
|
||||
|
||||
计算云 renjianbo 密码!Rjb1219
|
||||
|
||||
|
||||
荣耀开放平台 手机号 15129026818 邮箱263303411@qq.com renjianbo1219
|
||||
|
||||
|
||||
curse 网站续费 https://cursor.com/cn/dashboard
|
||||
|
||||
Reference in New Issue
Block a user