diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index ea9293f..a39fd12 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -13,15 +13,30 @@ "state": { "type": "markdown", "state": { - "file": "docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md", + "file": "docs/cursor/cursor.md", "mode": "source", "source": false }, "icon": "lucide-file", - "title": "README" + "title": "cursor" + } + }, + { + "id": "42dcaa0fed1f392a", + "type": "leaf", + "state": { + "type": "markdown", + "state": { + "file": "个人笔记体系.md", + "mode": "source", + "source": false + }, + "icon": "lucide-file", + "title": "个人笔记体系" } } - ] + ], + "currentTab": 1 } ], "direction": "vertical" @@ -183,13 +198,24 @@ "bases:创建新数据库": false } }, - "active": "f1ecba89214e3cc5", + "active": "42dcaa0fed1f392a", "lastOpenFiles": [ - "docs/Obsidian笔记体系/Areas/05-进程与线程通信/Handler机制源码解析.md", + "docs/Obsidian笔记体系/Resources/工具/脚本库/log_analyzer.py", + "docs/Obsidian笔记体系/Resources/工具/脚本库/performance_monitor.sh", + "docs/Obsidian笔记体系/Resources/工具/脚本库/test_startup_time.sh", + "docs/Obsidian笔记体系/脚本库/performance_monitor.sh", + "docs/Obsidian笔记体系/脚本库", + "docs/Obsidian笔记体系/Resources/工具/脚本库/collect_logs.sh", + "docs/Obsidian笔记体系/Resources/工具/脚本库/install_apks.sh", + "docs/Obsidian笔记体系/Resources/工具/脚本库/README.md", + "docs/Obsidian笔记体系/Resources/工具/效率工具推荐/README.md", + "docs/cursor/cursor.md", + "个人笔记体系.md", + "docs/Obsidian/2026-01-05 个人文档管理.md", "docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md", + "docs/Obsidian笔记体系/Areas/05-进程与线程通信/Handler机制源码解析.md", "docs/Obsidian笔记体系/Areas/06-性能优化体系/内存优化(LeakCanary原理).md", "docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md", - "docs/cursor/cursor.md", "docs/Obsidian笔记体系/Templates/源码解析模板.md", "docs/Obsidian笔记体系/Templates/问题排查模板.md", "docs/Obsidian笔记体系/Templates/技术方案设计模板.md", @@ -206,20 +232,9 @@ "README.md", "PackageManagerService.md", "docs/Obsidian笔记体系/Areas/03-Window系统/README.md", - "docs/Obsidian笔记体系/Areas/04-资源与包管理/README.md", - "动态加载与热修复原理.md", - "docs/Obsidian笔记体系/Areas/03-Window系统/WindowManagerService架构.md", - "docs/Obsidian笔记体系/Areas/03-Window系统/SurfaceFlinger交互流程.md", - "docs/Obsidian笔记体系/Areas/03-Window系统/窗口类型与层级.md", "docs/Obsidian笔记体系/Areas/01-系统启动流程/Bootloader到Init.md.bak", "docs/Obsidian笔记体系/Config/自定义脚本/源码链接生成器.py", "docs/Obsidian笔记体系/Config/自定义脚本/自动生成日报.js", - "docs/Obsidian笔记体系/Config/主题与样式.css", - "docs/Obsidian笔记体系/Config/自定义脚本", - "docs/Obsidian笔记体系/Daily/templates", - "docs/Obsidian笔记体系/Archive/资源-历史会议记录", - "docs/Obsidian笔记体系/Archive/领域-已废弃API研究", - "docs/Obsidian笔记体系/Archive/项目-旧版ROM适配", - "docs/Obsidian笔记体系/Resources/会议与分享/内部技术分享记录" + "docs/Obsidian笔记体系/Config/主题与样式.css" ] } \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md b/docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md index 74c45e6..77df838 100644 --- a/docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md +++ b/docs/Obsidian笔记体系/Areas/05-进程与线程通信/README.md @@ -1,4 +1,4 @@ -# 05-进程与线程通信 +# 05-进程与线程通信 本目录包含Android系统中进程与线程通信相关技术的深入分析和源码解析。涵盖了Binder机制、Handler机制、AIDL/HIDL、跨进程同步等核心内容。 diff --git a/docs/Obsidian笔记体系/Areas/06-性能优化体系/README.md b/docs/Obsidian笔记体系/Areas/06-性能优化体系/README.md index 425621e..6fa33af 100644 --- a/docs/Obsidian笔记体系/Areas/06-性能优化体系/README.md +++ b/docs/Obsidian笔记体系/Areas/06-性能优化体系/README.md @@ -1 +1,84 @@ # 06-性能优化体系 + +## 概述 + +性能优化是Android开发中的核心技能之一,涉及启动速度、内存管理、流畅度、功耗等多个维度。本目录系统性地整理了Android性能优化的方法论、工具链和实践经验。 + +## 目录结构 + +### 1. 启动优化方法论 +- 冷启动、温启动、热启动的区别 +- 启动时间测量方法 +- 启动优化策略与实践 + +### 2. 内存优化(LeakCanary原理) +- 内存泄漏检测原理 +- LeakCanary工作机制 +- 常见内存泄漏场景与解决方案 + +### 3. 流畅度(Choreographer+VSYNC) +- VSYNC机制原理 +- Choreographer源码解析 +- 卡顿分析与优化 + +### 4. 功耗优化工具链 +- 功耗分析工具 +- 电量消耗优化策略 +- 后台任务管理 + +## 性能优化原则 + +### 1. 测量优先 +- 先测量,再优化 +- 使用专业工具获取准确数据 +- 建立性能基线 + +### 2. 系统化思考 +- 从架构层面考虑优化 +- 避免局部优化导致全局问题 +- 平衡性能与可维护性 + +### 3. 持续监控 +- 建立性能监控体系 +- 设置性能告警阈值 +- 定期性能回归测试 + +## 性能指标 + +### 启动时间 +- **冷启动**: < 2秒 +- **热启动**: < 500ms +- **首屏渲染**: < 1秒 + +### 内存 +- **峰值内存**: 根据设备配置设定上限 +- **内存泄漏**: 0个 +- **GC频率**: 尽量减少Full GC + +### 流畅度 +- **FPS**: 稳定在60fps +- **掉帧率**: < 1% +- **ANR率**: < 0.1% + +### 功耗 +- **待机功耗**: < 5mA +- **使用功耗**: 根据场景设定 +- **后台功耗**: 最小化 + +## 工具链 + +### 官方工具 +- **Android Profiler**: 内存、CPU、网络分析 +- **Systrace/Perfetto**: 系统级性能分析 +- **Battery Historian**: 功耗分析 + +### 第三方工具 +- **LeakCanary**: 内存泄漏检测 +- **BlockCanary**: 主线程阻塞检测 +- **Matrix**: 腾讯开源性能监控框架 + +## 相关链接 + +- [[05-进程与线程通信]] +- [[09-调试与工具链]] +- [[MOCs/Android Framework知识体系图]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/06-性能优化体系/内存优化(LeakCanary原理).md b/docs/Obsidian笔记体系/Areas/06-性能优化体系/内存优化(LeakCanary原理).md index d85f301..c9b1562 100644 --- a/docs/Obsidian笔记体系/Areas/06-性能优化体系/内存优化(LeakCanary原理).md +++ b/docs/Obsidian笔记体系/Areas/06-性能优化体系/内存优化(LeakCanary原理).md @@ -1 +1,410 @@ # 内存优化(LeakCanary原理) + +## 概述 + +内存泄漏是Android开发中的常见问题,会导致应用内存占用持续增长,最终可能引发OOM(Out of Memory)崩溃。LeakCanary是Square公司开源的内存泄漏检测工具,本文档深入解析其工作原理和使用方法。 + +## 内存泄漏基础 + +### 什么是内存泄漏 + +内存泄漏是指程序在运行过程中,由于某些原因导致已分配的内存无法被回收,造成内存浪费和潜在的性能问题。 + +### Android中的内存泄漏场景 + +1. **静态变量持有Context** +```java +// 错误示例 +public class MyApplication { + private static Context sContext; // 持有Activity引用 +} + +// 正确做法 +public class MyApplication { + private static Context sAppContext; // 使用Application Context +} +``` + +2. **非静态内部类持有外部类引用** +```java +// 错误示例 +public class MainActivity extends Activity { + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + // 隐式持有MainActivity引用 + } + }; +} + +// 正确做法:使用静态内部类 + WeakReference +public class MainActivity extends Activity { + private static class MyHandler extends Handler { + private WeakReference mActivityRef; + + MyHandler(MainActivity activity) { + mActivityRef = new WeakReference<>(activity); + } + + @Override + public void handleMessage(Message msg) { + MainActivity activity = mActivityRef.get(); + if (activity != null) { + // 使用activity + } + } + } +} +``` + +3. **监听器未注销** +```java +// 错误示例 +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + EventBus.getDefault().register(this); // 注册但未注销 + } +} + +// 正确做法 +@Override +protected void onDestroy() { + super.onDestroy(); + EventBus.getDefault().unregister(this); +} +``` + +4. **资源未关闭** +```java +// 错误示例 +FileInputStream fis = new FileInputStream(file); +// 使用后未关闭 + +// 正确做法:使用try-with-resources +try (FileInputStream fis = new FileInputStream(file)) { + // 使用fis +} // 自动关闭 +``` + +## LeakCanary工作原理 + +### 核心机制 + +LeakCanary通过以下步骤检测内存泄漏: + +1. **对象引用监控**: 监控Activity/Fragment等关键对象的生命周期 +2. **弱引用检测**: 使用WeakReference + ReferenceQueue检测对象是否被回收 +3. **堆转储分析**: 当检测到泄漏时,dump堆内存进行分析 +4. **泄漏路径分析**: 使用Shark库分析GC Root到泄漏对象的引用链 + +### 工作流程 + +``` +Activity创建 + ↓ +LeakCanary.watch() 监控 + ↓ +Activity销毁 + ↓ +等待5秒(GC时间) + ↓ +检查对象是否被回收 + ↓ +未回收 → 触发堆转储 + ↓ +分析引用链 + ↓ +生成泄漏报告 +``` + +### 源码关键点 + +#### 1. ObjectWatcher + +```java +// 监控对象是否被回收 +public class ObjectWatcher { + private final ReferenceQueue queue = new ReferenceQueue<>(); + private final Map watchedObjects = new HashMap<>(); + + public void watch(Object watchedObject, String referenceName) { + KeyedWeakReference reference = new KeyedWeakReference( + watchedObject, referenceName, queue, clock); + watchedObjects.put(key, reference); + } +} +``` + +#### 2. HeapDumper + +```java +// 堆转储 +public interface HeapDumper { + File dumpHeap(); +} +``` + +#### 3. HeapAnalyzer + +```java +// 分析堆转储文件 +public class HeapAnalyzer { + public AnalysisResult checkForLeaks(File heapDumpFile) { + // 使用Shark库分析hprof文件 + // 查找GC Root到泄漏对象的路径 + } +} +``` + +## LeakCanary集成 + +### 添加依赖 + +```gradle +dependencies { + // LeakCanary + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12' +} +``` + +### 自动安装(无需代码) + +LeakCanary 2.0+ 使用ContentProvider自动初始化,无需手动配置。 + +### 手动监控 + +```java +// 监控自定义对象 +LeakCanary.INSTANCE.getObjectWatcher().watch( + myObject, + "MyObject被监控" +); +``` + +## 常见内存泄漏案例 + +### 1. Handler泄漏 + +**问题代码**: +```java +public class MainActivity extends Activity { + private Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + // Handler持有MainActivity的隐式引用 + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // 发送延迟消息 + mHandler.sendEmptyMessageDelayed(0, 60000); + } +} +``` + +**解决方案**: +```java +public class MainActivity extends Activity { + private static class MyHandler extends Handler { + private WeakReference mActivityRef; + + MyHandler(MainActivity activity) { + mActivityRef = new WeakReference<>(activity); + } + + @Override + public void handleMessage(Message msg) { + MainActivity activity = mActivityRef.get(); + if (activity == null) { + return; + } + // 处理消息 + } + } + + private MyHandler mHandler = new MyHandler(this); + + @Override + protected void onDestroy() { + super.onDestroy(); + mHandler.removeCallbacksAndMessages(null); + } +} +``` + +### 2. 单例持有Context + +**问题代码**: +```java +public class AppManager { + private static AppManager sInstance; + private Context mContext; + + private AppManager(Context context) { + mContext = context; // 可能持有Activity + } + + public static AppManager getInstance(Context context) { + if (sInstance == null) { + sInstance = new AppManager(context); + } + return sInstance; + } +} +``` + +**解决方案**: +```java +public class AppManager { + private static AppManager sInstance; + private Context mContext; + + private AppManager(Context context) { + // 使用Application Context + mContext = context.getApplicationContext(); + } + + public static AppManager getInstance(Context context) { + if (sInstance == null) { + sInstance = new AppManager(context); + } + return sInstance; + } +} +``` + +### 3. 匿名内部类 + +**问题代码**: +```java +public class MainActivity extends Activity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // 匿名内部类持有外部类引用 + new Thread(new Runnable() { + @Override + public void run() { + // 长时间运行的任务 + while (true) { + // ... + } + } + }).start(); + } +} +``` + +**解决方案**: +```java +public class MainActivity extends Activity { + private static class MyRunnable implements Runnable { + private WeakReference mActivityRef; + + MyRunnable(MainActivity activity) { + mActivityRef = new WeakReference<>(activity); + } + + @Override + public void run() { + MainActivity activity = mActivityRef.get(); + if (activity == null) { + return; + } + // 执行任务 + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + new Thread(new MyRunnable(this)).start(); + } +} +``` + +## 内存优化最佳实践 + +### 1. 使用Application Context + +```java +// 优先使用Application Context +Context appContext = context.getApplicationContext(); +``` + +### 2. 及时释放资源 + +```java +@Override +protected void onDestroy() { + super.onDestroy(); + // 注销监听器 + // 取消网络请求 + // 停止动画 + // 释放资源 +} +``` + +### 3. 使用WeakReference + +```java +// 对于可能持有Activity引用的对象,使用WeakReference +private WeakReference mActivityRef; +``` + +### 4. 避免静态变量持有View/Context + +```java +// 错误 +private static TextView sTextView; + +// 正确:使用WeakReference或避免静态变量 +``` + +### 5. 使用对象池 + +```java +// 复用对象,减少GC压力 +ObjectPool pool = new ObjectPool<>(10); +MyObject obj = pool.acquire(); +// 使用后归还 +pool.release(obj); +``` + +## 内存分析工具 + +### 1. Android Profiler + +- 实时内存监控 +- 堆转储分析 +- 内存分配追踪 + +### 2. MAT (Memory Analyzer Tool) + +- 分析hprof文件 +- 查找内存泄漏 +- 查看对象引用关系 + +### 3. LeakCanary + +- 自动检测泄漏 +- 可视化引用链 +- 开发阶段使用 + +## 内存优化指标 + +- **峰值内存**: 根据设备配置设定上限(如512MB) +- **内存泄漏**: 0个 +- **GC频率**: 尽量减少Full GC +- **内存抖动**: 避免频繁分配/释放 + +## 相关链接 + +- [[README]] +- [[09-调试与工具链]] +- [[05-进程与线程通信]] diff --git a/docs/Obsidian笔记体系/Areas/06-性能优化体系/功耗优化工具链.md b/docs/Obsidian笔记体系/Areas/06-性能优化体系/功耗优化工具链.md index 7d9bb61..588c8a1 100644 --- a/docs/Obsidian笔记体系/Areas/06-性能优化体系/功耗优化工具链.md +++ b/docs/Obsidian笔记体系/Areas/06-性能优化体系/功耗优化工具链.md @@ -1 +1,305 @@ # 功耗优化工具链 + +## 概述 + +功耗优化是移动应用开发中的重要环节,直接影响用户体验和设备续航。本文档介绍Android功耗优化的工具链、分析方法和优化策略。 + +## 功耗分析工具 + +### 1. Battery Historian + +Google官方提供的功耗分析工具,可以分析设备的电量消耗情况。 + +#### 安装与使用 + +```bash +# 安装Battery Historian +go get -u github.com/google/battery-historian + +# 启动服务 +cd $GOPATH/src/github.com/google/battery-historian +go run cmd/battery-historian/battery-historian.go +``` + +#### 数据采集 + +```bash +# 重置电池统计 +adb shell dumpsys batterystats --reset + +# 执行测试场景 +# ... 进行应用操作 ... + +# 导出数据 +adb bugreport > bugreport.txt +``` + +#### 关键指标 + +- **Wake Lock**: 唤醒锁持有时间 +- **CPU**: CPU使用率 +- **Network**: 网络流量 +- **GPS**: GPS使用情况 +- **Screen**: 屏幕亮度与唤醒时间 + +### 2. Android Profiler + +Android Studio内置的性能分析工具,可以实时监控功耗。 + +#### 使用步骤 + +1. 连接设备 +2. 打开Android Profiler +3. 选择Energy标签 +4. 监控电量消耗 + +#### 功能特点 + +- 实时监控 +- 可视化展示 +- 支持录制和回放 + +### 3. dumpsys batterystats + +系统命令,可以获取详细的电池统计信息。 + +```bash +# 查看电池统计 +adb shell dumpsys batterystats + +# 查看特定应用的功耗 +adb shell dumpsys batterystats com.example.app + +# 重置统计 +adb shell dumpsys batterystats --reset +``` + +### 4. Power Monitor + +硬件级功耗监控工具,需要支持Power Monitor的设备。 + +## 功耗优化策略 + +### 1. CPU优化 + +#### 减少CPU唤醒 + +```java +// 避免频繁唤醒CPU +// 使用JobScheduler替代AlarmManager +JobScheduler jobScheduler = + (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); +JobInfo jobInfo = new JobInfo.Builder(1, new ComponentName(this, MyJobService.class)) + .setPeriodic(15 * 60 * 1000) // 15分钟 + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) + .build(); +jobScheduler.schedule(jobInfo); +``` + +#### 优化算法复杂度 + +- 使用高效的数据结构 +- 避免不必要的循环 +- 使用缓存减少计算 + +#### 后台任务优化 + +```java +// 使用WorkManager管理后台任务 +WorkRequest uploadWork = new OneTimeWorkRequest.Builder(UploadWorker.class) + .setConstraints(new Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .setRequiresCharging(true) + .build()) + .build(); +WorkManager.getInstance(context).enqueue(uploadWork); +``` + +### 2. 网络优化 + +#### 批量请求 + +```java +// 合并多个小请求为一个批量请求 +// 减少网络唤醒次数 +``` + +#### 使用缓存 + +```java +// 使用HTTP缓存减少网络请求 +CacheControl cacheControl = new CacheControl.Builder() + .maxAge(1, TimeUnit.HOURS) + .build(); +``` + +#### 压缩数据 + +```java +// 使用Gzip压缩 +// 减少传输数据量 +``` + +### 3. Wake Lock管理 + +#### 及时释放Wake Lock + +```java +PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); +WakeLock wakeLock = powerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag"); + +try { + wakeLock.acquire(); + // 执行需要保持唤醒的操作 +} finally { + if (wakeLock.isHeld()) { + wakeLock.release(); + } +} +``` + +#### 使用超时机制 + +```java +// 设置超时,避免长时间持有 +wakeLock.acquire(10 * 60 * 1000L); // 10分钟超时 +``` + +### 4. 定位服务优化 + +#### 使用低功耗定位 + +```java +LocationRequest locationRequest = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_LOW_POWER) + .setInterval(60000) // 1分钟 + .setMaxWaitTime(5 * 60 * 1000); // 5分钟最大等待 +``` + +#### 及时停止定位 + +```java +// 不需要定位时立即停止 +locationManager.removeUpdates(locationListener); +``` + +### 5. 屏幕优化 + +#### 降低屏幕亮度 + +```java +// 根据环境光自动调整 +WindowManager.LayoutParams params = getWindow().getAttributes(); +params.screenBrightness = 0.5f; // 50%亮度 +getWindow().setAttributes(params); +``` + +#### 减少屏幕唤醒时间 + +```java +// 设置屏幕超时时间 +getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); +// 使用后及时清除 +getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); +``` + +### 6. 后台任务优化 + +#### 使用Doze模式 + +```java +// 适配Doze模式 +// 使用白名单机制 +PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE); +boolean isIgnoringBatteryOptimizations = + powerManager.isIgnoringBatteryOptimizations(getPackageName()); + +if (!isIgnoringBatteryOptimizations) { + Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); + intent.setData(Uri.parse("package:" + getPackageName())); + startActivity(intent); +} +``` + +#### 延迟非紧急任务 + +```java +// 使用JobScheduler延迟执行 +JobInfo jobInfo = new JobInfo.Builder(1, componentName) + .setMinimumLatency(30 * 60 * 1000) // 延迟30分钟 + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) + .build(); +``` + +## 功耗测试方法 + +### 1. 基准测试 + +```bash +# 1. 重置电池统计 +adb shell dumpsys batterystats --reset + +# 2. 执行测试场景(30分钟) +# 模拟用户正常使用 + +# 3. 导出数据 +adb bugreport > bugreport.txt + +# 4. 分析Battery Historian报告 +``` + +### 2. 对比测试 + +- 优化前后对比 +- 竞品对比 +- 不同设备对比 + +### 3. 场景测试 + +- 待机场景 +- 使用场景 +- 后台场景 + +## 常见问题 + +### 1. Wake Lock泄漏 + +**症状**: 设备无法进入休眠 + +**排查**: +```bash +adb shell dumpsys power +``` + +**解决**: 检查所有Wake Lock的acquire/release配对 + +### 2. 后台网络请求过多 + +**症状**: 待机时仍有网络流量 + +**排查**: Battery Historian查看Network统计 + +**解决**: 使用JobScheduler批量处理 + +### 3. GPS持续定位 + +**症状**: 定位服务一直运行 + +**排查**: Battery Historian查看GPS统计 + +**解决**: 及时停止定位服务 + +## 最佳实践 + +1. **最小化原则**: 只做必要的工作 +2. **批量处理**: 合并多个小任务 +3. **延迟执行**: 非紧急任务延迟处理 +4. **及时释放**: 用完资源立即释放 +5. **监控告警**: 建立功耗监控体系 + +## 相关链接 + +- [[README]] +- [[启动优化方法论]] +- [[09-调试与工具链/Systrace_Perfetto全解读]] diff --git a/docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md b/docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md index 6e57f60..4f3745b 100644 --- a/docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md +++ b/docs/Obsidian笔记体系/Areas/06-性能优化体系/启动优化方法论.md @@ -1 +1,427 @@ # 启动优化方法论 + +## 概述 + +应用启动速度直接影响用户体验,是性能优化的重要指标。本文档系统介绍Android应用启动优化的方法论、测量工具和优化策略。 + +## 启动类型 + +### 1. 冷启动(Cold Start) + +**定义**: 应用进程不存在,系统需要创建新进程并初始化应用。 + +**特点**: +- 耗时最长 +- 需要加载所有资源 +- 创建Application和主Activity + +**时间范围**: 通常2-5秒 + +### 2. 温启动(Warm Start) + +**定义**: 应用进程存在但Activity被销毁,需要重新创建Activity。 + +**特点**: +- 进程已存在 +- 只需创建Activity +- 比冷启动快 + +**时间范围**: 通常1-3秒 + +### 3. 热启动(Hot Start) + +**定义**: 应用进程和Activity都存在,只需将Activity带到前台。 + +**特点**: +- 最快 +- 只需恢复UI状态 +- 几乎不需要初始化 + +**时间范围**: 通常< 500ms + +## 启动时间测量 + +### 1. adb命令测量 + +```bash +# 测量启动时间 +adb shell am start -W -n com.example.app/.MainActivity + +# 输出示例: +# Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.example.app/.MainActivity } +# Status: ok +# Activity: com.example.app/.MainActivity +# ThisTime: 500 +# TotalTime: 500 +# WaitTime: 520 +``` + +**指标说明**: +- **ThisTime**: 最后一个Activity启动耗时 +- **TotalTime**: 所有Activity启动耗时 +- **WaitTime**: AMS启动Activity总耗时 + +### 2. 代码埋点测量 + +```java +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + long startTime = System.currentTimeMillis(); + super.onCreate(savedInstanceState); + + // 初始化工作 + + long endTime = System.currentTimeMillis(); + Log.d("Startup", "onCreate耗时: " + (endTime - startTime) + "ms"); + } + + @Override + public void onWindowFocusChanged(boolean hasFocus) { + super.onWindowFocusChanged(hasFocus); + if (hasFocus) { + // 首帧渲染完成 + long renderTime = System.currentTimeMillis() - getIntent().getLongExtra("start_time", 0); + Log.d("Startup", "首帧渲染耗时: " + renderTime + "ms"); + } + } +} +``` + +### 3. Systrace/Perfetto分析 + +```bash +# 使用Systrace +python systrace.py -t 10 -o trace.html sched freq idle am wm gfx view binder_driver hal dalvik camera input res + +# 使用Perfetto +# 通过Android Studio的Profiler录制 +``` + +**关键指标**: +- **Application.onCreate**: Application初始化时间 +- **Activity.onCreate**: Activity创建时间 +- **inflate**: 布局解析时间 +- **measure/layout/draw**: 视图测量、布局、绘制时间 + +### 4. 首屏渲染时间(TTI) + +```java +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // 监听首屏渲染 + View rootView = findViewById(android.R.id.content); + rootView.getViewTreeObserver().addOnPreDrawListener( + new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + rootView.getViewTreeObserver().removeOnPreDrawListener(this); + // 首屏已渲染 + logTTI(); + return true; + } + } + ); + } +} +``` + +## 启动优化策略 + +### 1. Application优化 + +#### 延迟初始化 + +```java +public class MyApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + // 立即初始化:必须的、轻量的 + initCrashHandler(); + + // 延迟初始化:非关键的、耗时的 + initInBackground(); + } + + private void initInBackground() { + new Thread(() -> { + // 在后台线程初始化 + initHeavyLibrary(); + initThirdPartySDK(); + }).start(); + } +} +``` + +#### 使用启动器框架 + +```java +// 使用Startup库管理初始化任务 +public class MyApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + AppStartup.initializeComponent(this, MyStartupInitializer.class); + } +} +``` + +### 2. 主线程优化 + +#### 减少主线程工作 + +```java +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // 避免在主线程做耗时操作 + // ❌ 错误:同步网络请求 + // String data = networkRequest(); + + // ✅ 正确:异步加载 + loadDataAsync(); + + setContentView(R.layout.activity_main); + } + + private void loadDataAsync() { + new Thread(() -> { + String data = networkRequest(); + runOnUiThread(() -> { + updateUI(data); + }); + }).start(); + } +} +``` + +#### 使用IdleHandler延迟非关键任务 + +```java +Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { + @Override + public boolean queueIdle() { + // 主线程空闲时执行 + initNonCriticalComponents(); + return false; // false表示只执行一次 + } +}); +``` + +### 3. 布局优化 + +#### 减少布局层级 + +```xml + + + + + + + + + + + + + +``` + +#### 使用ViewStub延迟加载 + +```xml + + +``` + +```java +// 需要时再加载 +ViewStub viewStub = findViewById(R.id.view_stub); +viewStub.inflate(); +``` + +#### 优化布局inflate + +```java +// 使用AsyncLayoutInflater异步加载布局 +new AsyncLayoutInflater(this).inflate( + R.layout.activity_main, + null, + (view, resid, parent) -> { + setContentView(view); + // 布局已加载完成 + } +); +``` + +### 4. 资源优化 + +#### 减少启动时加载的资源 + +```java +// 延迟加载大图片 +// 使用占位图 +ImageView imageView = findViewById(R.id.image); +imageView.setImageResource(R.drawable.placeholder); + +// 异步加载 +Glide.with(this) + .load(imageUrl) + .into(imageView); +``` + +#### 使用资源预加载 + +```java +// 在Application中预加载常用资源 +public class MyApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + // 预加载资源到内存 + preloadResources(); + } + + private void preloadResources() { + new Thread(() -> { + // 预加载常用drawable + Resources res = getResources(); + res.getDrawable(R.drawable.common_icon); + }).start(); + } +} +``` + +### 5. 多进程优化 + +```xml + + + + +``` + +**优点**: +- 主进程启动更快 +- 避免主进程OOM +- 隔离崩溃影响 + +**缺点**: +- 进程间通信开销 +- 内存占用增加 + +### 6. 类加载优化 + +#### 减少类数量 + +```java +// 使用ProGuard/R8混淆和优化 +// build.gradle +android { + buildTypes { + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), + 'proguard-rules.pro' + } + } +} +``` + +#### 使用MultiDex优化 + +```java +// 对于方法数超过65535的应用 +android { + defaultConfig { + multiDexEnabled true + } +} + +dependencies { + implementation 'androidx.multidex:multidex:2.0.1' +} +``` + +### 7. 启动画面优化 + +#### 使用Splash Screen API(Android 12+) + +```java +// 使用新的Splash Screen API +// 提供更好的启动体验 +``` + +#### 传统启动画面 + +```java +// 快速显示启动画面 +// 避免白屏/黑屏 + +``` + +## 启动优化检查清单 + +### Application层 +- [ ] 延迟非关键初始化 +- [ ] 使用后台线程初始化耗时任务 +- [ ] 避免在Application中做网络请求 +- [ ] 使用启动器框架管理初始化顺序 + +### Activity层 +- [ ] 减少onCreate中的工作 +- [ ] 异步加载数据 +- [ ] 使用ViewStub延迟加载 +- [ ] 优化布局层级 + +### 资源层 +- [ ] 减少启动时加载的资源 +- [ ] 使用占位图 +- [ ] 延迟加载大图片 +- [ ] 优化资源大小 + +### 代码层 +- [ ] 减少类数量(使用ProGuard) +- [ ] 避免静态初始化块中的耗时操作 +- [ ] 优化依赖库加载 + +## 性能指标 + +### 目标值 +- **冷启动**: < 2秒 +- **温启动**: < 1秒 +- **热启动**: < 500ms +- **首屏渲染**: < 1秒 + +### 测量方法 +1. 使用adb命令测量 +2. 代码埋点测量 +3. Systrace/Perfetto分析 +4. 用户感知时间测量 + +## 相关链接 + +- [[README]] +- [[流畅度(Choreographer+VSYNC)]] +- [[09-调试与工具链/Systrace_Perfetto全解读]] diff --git a/docs/Obsidian笔记体系/Areas/06-性能优化体系/流畅度(Choreographer+VSYNC).md b/docs/Obsidian笔记体系/Areas/06-性能优化体系/流畅度(Choreographer+VSYNC).md index 44fb4e1..de29b62 100644 --- a/docs/Obsidian笔记体系/Areas/06-性能优化体系/流畅度(Choreographer+VSYNC).md +++ b/docs/Obsidian笔记体系/Areas/06-性能优化体系/流畅度(Choreographer+VSYNC).md @@ -1 +1,499 @@ # 流畅度(Choreographer+VSYNC) + +## 概述 + +流畅度是Android应用性能的核心指标之一,直接影响用户体验。本文档深入解析VSYNC机制和Choreographer的工作原理,以及如何分析和优化应用流畅度。 + +## VSYNC机制 + +### 什么是VSYNC + +VSYNC(Vertical Synchronization,垂直同步)是显示系统与GPU之间的同步机制,确保帧在正确的时机刷新到屏幕。 + +### VSYNC的作用 + +1. **防止画面撕裂**: 避免在画面刷新过程中显示不完整的帧 +2. **统一刷新时机**: 所有绘制操作在VSYNC信号到来时同步执行 +3. **保证流畅度**: 确保以固定频率(通常60Hz)刷新画面 + +### VSYNC工作流程 + +``` +VSYNC信号(16.67ms间隔,60Hz) + ↓ +SurfaceFlinger接收VSYNC + ↓ +通知应用层开始绘制 + ↓ +应用执行measure/layout/draw + ↓ +提交帧到SurfaceFlinger + ↓ +下一个VSYNC时显示 +``` + +### VSYNC时间线 + +``` +Frame N-1 Frame N Frame N+1 + | | | +VSYNC ──────> VSYNC ──────> VSYNC + | | | + |<-- 16.67ms --><-- 16.67ms --> +``` + +**关键时间点**: +- **VSYNC间隔**: 16.67ms(60Hz) +- **绘制窗口**: 必须在16.67ms内完成 +- **超过时间**: 会掉帧(Jank) + +## Choreographer源码解析 + +### Choreographer的作用 + +Choreographer是Android系统提供的帧调度器,负责协调应用层的绘制时机与VSYNC信号同步。 + +### 核心类结构 + +```java +public final class Choreographer { + // VSYNC回调接口 + private final FrameDisplayEventReceiver mDisplayEventReceiver; + + // 回调队列 + private final CallbackQueue[] mCallbackQueues; + + // 当前帧时间 + private long mFrameTimeNanos; + + // 帧间隔(纳秒) + private static final long FRAME_INTERVAL_NANOS = 16_666_667L; // 16.67ms +} +``` + +### 关键方法 + +#### 1. postFrameCallback + +```java +public void postFrameCallback(FrameCallback callback) { + postFrameCallbackDelayed(callback, 0); +} + +public void postFrameCallbackDelayed(FrameCallback callback, long delayMillis) { + if (callback == null) { + throw new IllegalArgumentException("callback must not be null"); + } + + postCallbackDelayedInternal(CALLBACK_ANIMATION, + callback, FRAME_CALLBACK_TOKEN, delayMillis); +} +``` + +**作用**: 注册一个回调,在下一帧绘制时执行。 + +**使用场景**: +- 动画帧回调 +- 自定义绘制 +- 性能监控 + +#### 2. doFrame + +```java +void doFrame(long frameTimeNanos, int frame) { + final long startNanos = System.nanoTime(); + final long jitterNanos = startNanos - frameTimeNanos; + + if (jitterNanos >= mFrameIntervalNanos) { + // 掉帧检测 + final long skippedFrames = jitterNanos / mFrameIntervalNanos; + if (skippedFrames >= SKIPPED_FRAME_WARNING_LIMIT) { + Log.i(TAG, "Skipped " + skippedFrames + " frames! " + + "The application may be doing too much work on its main thread."); + } + } + + // 执行回调 + mFrameInfo.markInputHandlingStart(); + doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos); + + mFrameInfo.markAnimationsStart(); + doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos); + + mFrameInfo.markPerformTraversalsStart(); + doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos); + + doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos); +} +``` + +**回调执行顺序**: +1. **INPUT**: 输入事件处理 +2. **ANIMATION**: 动画执行 +3. **TRAVERSAL**: 视图遍历(measure/layout/draw) +4. **COMMIT**: 提交帧 + +### FrameDisplayEventReceiver + +```java +private final class FrameDisplayEventReceiver extends DisplayEventReceiver + implements Runnable { + @Override + public void onVsync(long timestampNanos, int builtInDisplayId, int frame) { + // 接收VSYNC信号 + long now = System.nanoTime(); + if (timestampNanos > now) { + timestampNanos = now; + } + + if (mHavePendingVsync) { + Log.w(TAG, "Already have a pending vsync event. There should only be " + + "one at a time."); + } else { + mHavePendingVsync = true; + } + + mTimestampNanos = timestampNanos; + mFrame = frame; + Message msg = Message.obtain(mHandler, this); + msg.setAsynchronous(true); + mHandler.sendMessageAtTime(msg, timestampNanos / TimeUtils.NANOS_PER_MS); + } + + @Override + public void run() { + mHavePendingVsync = false; + doFrame(mTimestampNanos, mFrame); + } +} +``` + +## 流畅度分析 + +### 1. 使用Systrace/Perfetto + +```bash +# 录制Systrace +python systrace.py -t 10 -o trace.html gfx view sched freq idle am wm + +# 关键指标: +# - Frame: 每一帧的耗时 +# - VSYNC: VSYNC信号 +# - UI Thread: 主线程执行情况 +``` + +**分析要点**: +- 查看Frame是否超过16.67ms +- 识别主线程阻塞 +- 查找耗时操作 + +### 2. 使用GPU Rendering Profile + +```java +// 在开发者选项中开启"GPU渲染模式分析" +// 或使用代码开启 +View.setLayerType(View.LAYER_TYPE_HARDWARE, null); +``` + +**指标说明**: +- **绿色线**: 16.67ms基准线 +- **蓝色**: 测量时间 +- **紫色**: 布局时间 +- **红色**: 绘制时间 + +### 3. 使用Choreographer监控 + +```java +public class FrameMonitor { + private Choreographer mChoreographer; + private long mLastFrameTimeNanos; + private int mDroppedFrames; + + public void start() { + mChoreographer = Choreographer.getInstance(); + mChoreographer.postFrameCallback(mFrameCallback); + } + + private Choreographer.FrameCallback mFrameCallback = + new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + if (mLastFrameTimeNanos != 0) { + long frameInterval = frameTimeNanos - mLastFrameTimeNanos; + if (frameInterval > 16_666_667L * 1.5) { + // 掉帧检测 + mDroppedFrames++; + Log.w("FrameMonitor", "Dropped frame: " + + (frameInterval / 1_000_000) + "ms"); + } + } + mLastFrameTimeNanos = frameTimeNanos; + mChoreographer.postFrameCallback(this); + } + }; +} +``` + +### 4. 使用BlockCanary + +```gradle +dependencies { + debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0' +} +``` + +```java +// 自动检测主线程阻塞 +// 超过阈值会弹出通知 +``` + +## 流畅度优化策略 + +### 1. 减少主线程耗时操作 + +```java +// ❌ 错误:在主线程做耗时操作 +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // 同步网络请求 + String data = networkRequest(); // 阻塞主线程 + updateUI(data); +} + +// ✅ 正确:异步处理 +@Override +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + // 异步加载 + loadDataAsync(); +} + +private void loadDataAsync() { + new Thread(() -> { + String data = networkRequest(); + runOnUiThread(() -> { + updateUI(data); + }); + }).start(); +} +``` + +### 2. 优化布局性能 + +#### 减少布局层级 + +```xml + + + + + + + + + + + + + +``` + +#### 使用include和merge + +```xml + + + + + + + + +``` + +#### 避免过度绘制 + +```java +// 开启过度绘制检测 +// 开发者选项 -> 显示过度绘制区域 + +// 优化方法: +// 1. 移除不必要的背景 +view.setBackground(null); + +// 2. 使用clipRect裁剪绘制区域 +canvas.clipRect(left, top, right, bottom); + +// 3. 使用ViewStub延迟加载 +``` + +### 3. 优化自定义View绘制 + +```java +public class CustomView extends View { + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + // ❌ 错误:在onDraw中创建对象 + // Paint paint = new Paint(); + + // ✅ 正确:复用对象 + if (mPaint == null) { + mPaint = new Paint(); + } + + // 避免在onDraw中做耗时计算 + // 预处理数据,缓存结果 + } + + private Paint mPaint; +} +``` + +### 4. 使用硬件加速 + +```xml + + + +``` + +```java +// 代码中开启 +view.setLayerType(View.LAYER_TYPE_HARDWARE, null); + +// 注意:硬件加速不是万能的 +// 某些操作(如clipPath)在硬件加速下可能更慢 +``` + +### 5. 优化动画性能 + +```java +// ❌ 错误:使用属性动画在复杂View上 +ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", 0, 100); +animator.start(); + +// ✅ 正确:使用ViewPropertyAnimator +view.animate() + .translationX(100) + .setDuration(300) + .start(); + +// ✅ 更优:使用硬件层 +view.setLayerType(View.LAYER_TYPE_HARDWARE, null); +view.animate() + .translationX(100) + .withEndAction(() -> { + view.setLayerType(View.LAYER_TYPE_NONE, null); + }) + .start(); +``` + +### 6. 使用RecyclerView优化列表 + +```java +// 优化RecyclerView性能 +recyclerView.setHasFixedSize(true); // 固定大小 +recyclerView.setItemViewCacheSize(20); // 增加缓存 +recyclerView.setDrawingCacheEnabled(true); + +// 使用DiffUtil更新数据 +DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(oldList, newList)); +diffResult.dispatchUpdatesTo(adapter); +``` + +### 7. 避免内存抖动 + +```java +// ❌ 错误:频繁创建对象 +for (int i = 0; i < 1000; i++) { + String str = new String("item" + i); // 每次循环创建新对象 + list.add(str); +} + +// ✅ 正确:复用对象或使用StringBuilder +StringBuilder sb = new StringBuilder(); +for (int i = 0; i < 1000; i++) { + sb.setLength(0); + sb.append("item").append(i); + list.add(sb.toString()); +} +``` + +## 掉帧(Jank)分析 + +### 掉帧原因 + +1. **主线程阻塞** + - 同步I/O操作 + - 复杂计算 + - 同步网络请求 + +2. **布局复杂** + - 嵌套层级过深 + - 过度绘制 + - 频繁measure/layout + +3. **内存问题** + - 频繁GC + - 内存抖动 + - 内存泄漏 + +4. **动画问题** + - 复杂动画计算 + - 未使用硬件加速 + - 动画冲突 + +### 掉帧检测 + +```java +// 使用Choreographer检测掉帧 +Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() { + @Override + public void doFrame(long frameTimeNanos) { + long currentTime = System.nanoTime(); + long frameInterval = currentTime - mLastFrameTime; + + if (frameInterval > 16_666_667L * 1.5) { + // 掉帧 + int droppedFrames = (int) (frameInterval / 16_666_667L); + Log.w("Jank", "Dropped " + droppedFrames + " frames"); + } + + mLastFrameTime = currentTime; + Choreographer.getInstance().postFrameCallback(this); + } +}); +``` + +## 性能指标 + +### 目标值 +- **FPS**: 稳定在60fps +- **帧耗时**: < 16.67ms +- **掉帧率**: < 1% +- **ANR率**: < 0.1% + +### 测量方法 +1. Systrace/Perfetto分析 +2. GPU Rendering Profile +3. Choreographer监控 +4. BlockCanary检测 + +## 最佳实践 + +1. **测量优先**: 先测量,找到瓶颈再优化 +2. **避免过度优化**: 不要过早优化 +3. **系统化思考**: 从架构层面考虑 +4. **持续监控**: 建立性能监控体系 +5. **用户感知**: 关注用户可感知的流畅度 + +## 相关链接 + +- [[README]] +- [[启动优化方法论]] +- [[内存优化(LeakCanary原理)]] +- [[09-调试与工具链/Systrace_Perfetto全解读]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/09-调试与工具链/ADB高级命令.md b/docs/Obsidian笔记体系/Areas/09-调试与工具链/ADB高级命令.md index 1674d74..8218b14 100644 --- a/docs/Obsidian笔记体系/Areas/09-调试与工具链/ADB高级命令.md +++ b/docs/Obsidian笔记体系/Areas/09-调试与工具链/ADB高级命令.md @@ -1 +1,537 @@ # ADB高级命令 + +## 概述 + +ADB (Android Debug Bridge) 是Android开发中最常用的命令行工具,用于与Android设备通信。本文档详细介绍ADB的高级用法和实用技巧。 + +## ADB基础 + +### 安装与配置 + +```bash +# 检查ADB版本 +adb version + +# 查看连接的设备 +adb devices + +# 查看设备详细信息 +adb devices -l +``` + +### 设备连接 + +```bash +# USB连接 +adb devices + +# 网络连接(需要先USB连接一次) +adb tcpip 5555 +adb connect <设备IP>:5555 + +# 断开网络连接 +adb disconnect <设备IP>:5555 + +# 切换回USB模式 +adb usb +``` + +## 日志相关命令 + +### 1. logcat基础 + +```bash +# 查看所有日志 +adb logcat + +# 清空日志缓冲区 +adb logcat -c + +# 查看指定tag的日志 +adb logcat -s TAG_NAME + +# 查看多个tag +adb logcat -s TAG1 TAG2 + +# 过滤日志级别 +adb logcat *:E # 只显示Error级别 +adb logcat *:W # 只显示Warning及以上 +``` + +### 2. logcat高级用法 + +```bash +# 按时间格式显示 +adb logcat -v time + +# 显示进程ID和线程ID +adb logcat -v threadtime + +# 显示颜色(需要终端支持) +adb logcat -v color + +# 显示所有信息(最详细) +adb logcat -v long + +# 保存日志到文件 +adb logcat > log.txt + +# 实时查看并保存 +adb logcat | tee log.txt + +# 按包名过滤 +adb logcat | grep com.example.app +``` + +### 3. 日志过滤技巧 + +```bash +# 使用grep过滤 +adb logcat | grep "关键词" + +# 排除某些tag +adb logcat | grep -v "TAG_NAME" + +# 组合过滤 +adb logcat | grep -E "关键词1|关键词2" + +# 按时间范围过滤(需要先保存日志) +adb logcat -t '01-01 12:00:00.000' +``` + +### 4. 日志级别 + +```bash +# 设置日志级别 +adb shell setprop log.tag.TAG_NAME VERBOSE +adb shell setprop log.tag.TAG_NAME DEBUG +adb shell setprop log.tag.TAG_NAME INFO +adb shell setprop log.tag.TAG_NAME WARN +adb shell setprop log.tag.TAG_NAME ERROR + +# 查看当前日志级别 +adb shell getprop log.tag.TAG_NAME +``` + +## 系统服务调试 + +### 1. dumpsys命令 + +```bash +# 查看所有可用的服务 +adb shell dumpsys -l + +# 查看Activity信息 +adb shell dumpsys activity + +# 查看Activity栈 +adb shell dumpsys activity activities + +# 查看当前Activity +adb shell dumpsys activity top + +# 查看Service信息 +adb shell dumpsys activity services + +# 查看内存信息 +adb shell dumpsys meminfo + +# 查看指定应用的内存 +adb shell dumpsys meminfo com.example.app + +# 查看电池信息 +adb shell dumpsys batterystats + +# 查看网络信息 +adb shell dumpsys netstats + +# 查看包信息 +adb shell dumpsys package com.example.app + +# 查看窗口信息 +adb shell dumpsys window + +# 查看输入法信息 +adb shell dumpsys input_method +``` + +### 2. Activity Manager命令 + +```bash +# 启动Activity +adb shell am start -n com.example.app/.MainActivity + +# 启动Activity并传递数据 +adb shell am start -n com.example.app/.MainActivity \ + -e key1 value1 -e key2 value2 + +# 启动Service +adb shell am startservice -n com.example.app/.MyService + +# 发送广播 +adb shell am broadcast -a android.intent.action.BOOT_COMPLETED + +# 强制停止应用 +adb shell am force-stop com.example.app + +# 杀死进程 +adb shell am kill com.example.app + +# 启动Activity并测量启动时间 +adb shell am start -W -n com.example.app/.MainActivity +``` + +### 3. Package Manager命令 + +```bash +# 安装APK +adb install app.apk + +# 安装并替换已存在的应用 +adb install -r app.apk + +# 安装到SD卡 +adb install -s app.apk + +# 卸载应用 +adb uninstall com.example.app + +# 保留数据卸载 +adb uninstall -k com.example.app + +# 查看已安装的包 +adb shell pm list packages + +# 查看指定应用的包信息 +adb shell pm list packages | grep com.example + +# 查看包路径 +adb shell pm path com.example.app + +# 清除应用数据 +adb shell pm clear com.example.app + +# 启用/禁用组件 +adb shell pm enable com.example.app/.MainActivity +adb shell pm disable com.example.app/.MainActivity +``` + +### 4. 输入事件模拟 + +```bash +# 点击屏幕坐标 +adb shell input tap 500 1000 + +# 滑动 +adb shell input swipe 300 1000 300 500 + +# 输入文本 +adb shell input text "Hello World" + +# 按键事件 +adb shell input keyevent KEYCODE_HOME +adb shell input keyevent KEYCODE_BACK +adb shell input keyevent KEYCODE_MENU + +# 长按 +adb shell input swipe 500 1000 500 1000 2000 +``` + +## 文件操作 + +### 1. 文件传输 + +```bash +# 推送文件到设备 +adb push local_file.txt /sdcard/ + +# 从设备拉取文件 +adb pull /sdcard/file.txt ./ + +# 查看设备文件 +adb shell ls /sdcard/ + +# 查看文件内容 +adb shell cat /sdcard/file.txt +``` + +### 2. 文件权限 + +```bash +# 修改文件权限 +adb shell chmod 755 /data/local/tmp/script.sh + +# 修改文件所有者 +adb shell chown system:system /data/local/tmp/file + +# 查看文件权限 +adb shell ls -l /data/local/tmp/ +``` + +## 性能数据采集 + +### 1. CPU信息 + +```bash +# 查看CPU使用率 +adb shell top + +# 查看指定进程的CPU使用率 +adb shell top -p + +# 查看CPU信息 +adb shell cat /proc/cpuinfo + +# 查看CPU频率 +adb shell cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq +``` + +### 2. 内存信息 + +```bash +# 查看内存使用情况 +adb shell dumpsys meminfo + +# 查看指定应用的内存 +adb shell dumpsys meminfo com.example.app + +# 查看系统内存 +adb shell cat /proc/meminfo + +# 查看进程内存映射 +adb shell cat /proc//maps +``` + +### 3. 网络信息 + +```bash +# 查看网络接口 +adb shell ifconfig + +# 查看网络连接 +adb shell netstat + +# 查看路由表 +adb shell ip route + +# 查看网络统计 +adb shell cat /proc/net/sockstat +``` + +### 4. 电池信息 + +```bash +# 查看电池状态 +adb shell dumpsys battery + +# 重置电池统计 +adb shell dumpsys batterystats --reset + +# 导出电池报告(需要配合bugreport) +adb bugreport +``` + +## 系统属性操作 + +### 1. 查看系统属性 + +```bash +# 查看所有属性 +adb shell getprop + +# 查看指定属性 +adb shell getprop ro.build.version.sdk + +# 查看属性列表(部分) +adb shell getprop | grep "ro\." +``` + +### 2. 设置系统属性 + +```bash +# 设置属性(需要root) +adb shell setprop property_name property_value + +# 设置日志级别 +adb shell setprop log.tag.TAG_NAME DEBUG +``` + +## 调试技巧 + +### 1. 查看进程信息 + +```bash +# 查看所有进程 +adb shell ps + +# 查看指定应用的进程 +adb shell ps | grep com.example.app + +# 查看进程树 +adb shell ps -A + +# 查看进程详细信息 +adb shell ps -ef +``` + +### 2. 查看线程信息 + +```bash +# 查看进程的所有线程 +adb shell ps -T -p + +# 查看线程堆栈 +adb shell kill -3 # 发送SIGQUIT信号,生成堆栈 +``` + +### 3. 网络调试 + +```bash +# 设置代理 +adb shell settings put global http_proxy : + +# 清除代理 +adb shell settings delete global http_proxy +adb shell settings delete global global_http_proxy_host +adb shell settings delete global global_http_proxy_port + +# 查看代理设置 +adb shell settings get global http_proxy +``` + +### 4. 权限调试 + +```bash +# 授予运行时权限 +adb shell pm grant com.example.app android.permission.CAMERA + +# 撤销权限 +adb shell pm revoke com.example.app android.permission.CAMERA + +# 查看应用权限 +adb shell dumpsys package com.example.app | grep permission +``` + +## 高级用法 + +### 1. 执行Shell命令 + +```bash +# 执行单条命令 +adb shell "ls -l /sdcard/" + +# 执行多条命令 +adb shell "cd /sdcard && ls -l" + +# 执行脚本 +adb shell sh /sdcard/script.sh +``` + +### 2. 端口转发 + +```bash +# 转发端口 +adb forward tcp:8080 tcp:8080 + +# 转发到Unix域套接字 +adb forward tcp:8080 local:/tmp/socket + +# 查看所有转发 +adb forward --list + +# 删除转发 +adb forward --remove tcp:8080 +``` + +### 3. 无线调试(Android 11+) + +```bash +# 配对设备(首次) +adb pair : +# 输入配对码 + +# 连接设备 +adb connect : + +# 查看已连接的设备 +adb devices +``` + +### 4. 多设备管理 + +```bash +# 指定设备执行命令 +adb -s shell ... + +# 查看设备序列号 +adb devices -l +``` + +## 实用脚本 + +### 1. 清理日志并重启 + +```bash +#!/bin/bash +adb logcat -c +adb shell reboot +``` + +### 2. 批量安装APK + +```bash +#!/bin/bash +for apk in *.apk; do + adb install -r "$apk" +done +``` + +### 3. 监控应用崩溃 + +```bash +#!/bin/bash +adb logcat | grep -i "fatal\|exception\|crash" +``` + +### 4. 性能数据采集 + +```bash +#!/bin/bash +# 采集CPU、内存、网络数据 +adb shell top -n 1 > cpu.txt +adb shell dumpsys meminfo > meminfo.txt +adb shell dumpsys netstats > netstats.txt +``` + +## 常见问题 + +### 1. 设备未识别 + +```bash +# 检查USB连接 +adb kill-server +adb start-server +adb devices +``` + +### 2. 权限不足 + +```bash +# 某些命令需要root权限 +adb root +adb remount +``` + +### 3. 日志过多 + +```bash +# 使用过滤器减少日志 +adb logcat -c # 清空缓冲区 +adb logcat *:E # 只显示错误 +``` + +## 相关链接 + +- [[README]] +- [[GDB_LLDB调试Native]] +- [[Systrace_Perfetto全解读]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/09-调试与工具链/GDB_LLDB调试Native.md b/docs/Obsidian笔记体系/Areas/09-调试与工具链/GDB_LLDB调试Native.md index ce03494..b183028 100644 --- a/docs/Obsidian笔记体系/Areas/09-调试与工具链/GDB_LLDB调试Native.md +++ b/docs/Obsidian笔记体系/Areas/09-调试与工具链/GDB_LLDB调试Native.md @@ -1 +1,538 @@ # GDB/LLDB调试Native + +## 概述 + +GDB和LLDB是调试Native代码(C/C++)的强大工具。在Android开发中,特别是Framework层和NDK开发,掌握这些调试工具至关重要。 + +## GDB基础 + +### GDB简介 + +GDB (GNU Debugger) 是Linux/Unix系统上最常用的调试器,支持C、C++、Java等多种语言。 + +### 安装GDB + +```bash +# Ubuntu/Debian +sudo apt-get install gdb + +# 检查版本 +gdb --version +``` + +### 基本用法 + +```bash +# 启动GDB +gdb program + +# 或者附加到运行中的进程 +gdb program + +# 加载core文件 +gdb program core +``` + +### 常用命令 + +```bash +# 运行程序 +(gdb) run +(gdb) r + +# 设置断点 +(gdb) break main +(gdb) break file.c:100 +(gdb) break function_name +(gdb) b main # 简写 + +# 查看断点 +(gdb) info breakpoints +(gdb) i b + +# 删除断点 +(gdb) delete 1 +(gdb) d 1 + +# 继续执行 +(gdb) continue +(gdb) c + +# 单步执行(进入函数) +(gdb) step +(gdb) s + +# 单步执行(不进入函数) +(gdb) next +(gdb) n + +# 查看变量 +(gdb) print variable_name +(gdb) p variable_name + +# 查看变量类型 +(gdb) ptype variable_name + +# 查看局部变量 +(gdb) info locals +(gdb) i locals + +# 查看函数参数 +(gdb) info args +(gdb) i args + +# 查看堆栈 +(gdb) backtrace +(gdb) bt + +# 切换堆栈帧 +(gdb) frame 1 +(gdb) f 1 + +# 查看当前代码 +(gdb) list +(gdb) l + +# 退出GDB +(gdb) quit +(gdb) q +``` + +## LLDB基础 + +### LLDB简介 + +LLDB是LLVM项目的一部分,是macOS和iOS开发中的标准调试器,也支持Linux和Android。 + +### 安装LLDB + +```bash +# macOS (Xcode自带) +# 或通过Homebrew +brew install llvm + +# 检查版本 +lldb --version +``` + +### 基本用法 + +```bash +# 启动LLDB +lldb program + +# 附加到进程 +lldb -p + +# 加载core文件 +lldb -c core program +``` + +### 常用命令 + +```bash +# 运行程序 +(lldb) run +(lldb) r + +# 设置断点 +(lldb) breakpoint set --name main +(lldb) breakpoint set --file file.c --line 100 +(lldb) b main # 简写 + +# 查看断点 +(lldb) breakpoint list +(lldb) br l + +# 删除断点 +(lldb) breakpoint delete 1 +(lldb) br del 1 + +# 继续执行 +(lldb) continue +(lldb) c + +# 单步执行(进入函数) +(lldb) step +(lldb) s + +# 单步执行(不进入函数) +(lldb) next +(lldb) n + +# 查看变量 +(lldb) print variable_name +(lldb) p variable_name + +# 查看变量类型 +(lldb) frame variable +(lldb) fr v + +# 查看局部变量 +(lldb) frame variable +(lldb) fr v + +# 查看堆栈 +(lldb) thread backtrace +(lldb) bt + +# 切换线程 +(lldb) thread select 1 +(lldb) th s 1 + +# 查看当前代码 +(lldb) source list +(lldb) l + +# 退出LLDB +(lldb) quit +(lldb) q +``` + +## Android Native调试 + +### 1. 使用GDB调试Android Native代码 + +#### 准备工作 + +```bash +# 1. 确保应用是可调试的 +# AndroidManifest.xml中设置 android:debuggable="true" + +# 2. 推送gdbserver到设备 +adb push $NDK/prebuilt/android-arm64/gdbserver/gdbserver /data/local/tmp/ + +# 3. 设置权限 +adb shell chmod 755 /data/local/tmp/gdbserver +``` + +#### 启动调试会话 + +```bash +# 1. 启动应用并获取PID +adb shell ps | grep com.example.app + +# 2. 在设备上启动gdbserver +adb shell /data/local/tmp/gdbserver :5039 --attach + +# 3. 端口转发 +adb forward tcp:5039 tcp:5039 + +# 4. 在主机上启动GDB +$NDK/prebuilt/linux-x86_64/bin/gdb + +# 5. 在GDB中连接 +(gdb) target remote :5039 + +# 6. 设置符号文件 +(gdb) file /path/to/your/library.so +(gdb) set solib-search-path /path/to/symbols +``` + +### 2. 使用LLDB调试Android Native代码 + +#### 准备工作 + +```bash +# 1. 使用lldb-server(Android NDK r21+) +adb push $NDK/toolchains/llvm/prebuilt/linux-x86_64/lib64/clang/*/lib/linux/aarch64/lldb-server /data/local/tmp/ + +# 2. 设置权限 +adb shell chmod 755 /data/local/tmp/lldb-server +``` + +#### 启动调试会话 + +```bash +# 1. 启动应用并获取PID +adb shell ps | grep com.example.app + +# 2. 在设备上启动lldb-server +adb shell /data/local/tmp/lldb-server platform --server --listen "*:5039" --attach + +# 3. 端口转发 +adb forward tcp:5039 tcp:5039 + +# 4. 在主机上启动LLDB +lldb + +# 5. 在LLDB中连接 +(lldb) platform select remote-android +(lldb) platform connect connect://localhost:5039 + +# 6. 加载符号 +(lldb) target create /path/to/your/library.so +``` + +### 3. Android Studio集成调试 + +Android Studio提供了图形化的Native调试界面: + +1. **配置调试器** + - Run -> Edit Configurations + - 选择"Debugger"标签 + - 选择"Native"调试器类型 + +2. **设置断点** + - 在Native代码中设置断点 + - 支持条件断点 + +3. **开始调试** + - 点击Debug按钮 + - 应用会在断点处暂停 + +## 高级调试技巧 + +### 1. 条件断点 + +```gdb +# GDB +(gdb) break file.c:100 if variable == 5 +(gdb) condition 1 variable > 10 +``` + +```lldb +# LLDB +(lldb) breakpoint set --file file.c --line 100 --condition 'variable == 5' +(lldb) breakpoint modify 1 --condition 'variable > 10' +``` + +### 2. 观察点(Watchpoint) + +```gdb +# GDB - 监控变量变化 +(gdb) watch variable_name +(gdb) watch *0x12345678 # 监控内存地址 +``` + +```lldb +# LLDB +(lldb) watchpoint set variable variable_name +(lldb) watchpoint set expression -- 0x12345678 +``` + +### 3. 内存操作 + +```gdb +# GDB +(gdb) x/10x 0x12345678 # 查看内存(16进制,10个单位) +(gdb) x/10i $pc # 查看指令 +(gdb) x/s 0x12345678 # 查看字符串 +``` + +```lldb +# LLDB +(lldb) memory read --format x --count 10 0x12345678 +(lldb) memory read --format instruction --count 10 $pc +(lldb) memory read --format cstring 0x12345678 +``` + +### 4. 寄存器操作 + +```gdb +# GDB +(gdb) info registers # 查看所有寄存器 +(gdb) print $rax # 查看特定寄存器 +(gdb) set $rax = 0x1234 # 设置寄存器值 +``` + +```lldb +# LLDB +(lldb) register read # 查看所有寄存器 +(lldb) register read rax # 查看特定寄存器 +(lldb) register write rax 0x1234 # 设置寄存器值 +``` + +### 5. 多线程调试 + +```gdb +# GDB +(gdb) info threads # 查看所有线程 +(gdb) thread 2 # 切换到线程2 +(gdb) thread apply all bt # 查看所有线程堆栈 +``` + +```lldb +# LLDB +(lldb) thread list # 查看所有线程 +(lldb) thread select 2 # 切换到线程2 +(lldb) thread backtrace all # 查看所有线程堆栈 +``` + +## 崩溃分析 + +### 1. 分析Core Dump + +```bash +# 生成core文件 +ulimit -c unlimited +./program + +# 使用GDB分析 +gdb program core +(gdb) bt # 查看堆栈 +(gdb) info registers # 查看寄存器 +``` + +### 2. 分析Tombstone(Android) + +```bash +# 获取tombstone文件 +adb pull /data/tombstones/tombstone_XX + +# 使用addr2line解析地址 +$NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-addr2line -e library.so
+ +# 或使用ndk-stack +$NDK/ndk-stack -sym /path/to/symbols -dump tombstone_XX +``` + +### 3. 使用GDB分析崩溃 + +```bash +# 1. 获取崩溃时的堆栈 +adb shell gdb -p +(gdb) bt + +# 2. 查看寄存器状态 +(gdb) info registers + +# 3. 查看内存内容 +(gdb) x/10x $sp # 查看栈内容 +``` + +## 实战案例 + +### 案例1:调试JNI调用 + +```java +// Java层 +public native void nativeMethod(int value); +``` + +```cpp +// Native层 +JNIEXPORT void JNICALL +Java_com_example_MainActivity_nativeMethod(JNIEnv *env, jobject thiz, jint value) { + // 设置断点 + int result = value * 2; + // ... +} +``` + +**调试步骤**: +1. 在Native方法中设置断点 +2. 从Java层调用Native方法 +3. 在断点处检查参数和局部变量 + +### 案例2:调试内存泄漏 + +```cpp +void* allocateMemory(size_t size) { + void* ptr = malloc(size); + // 设置断点,检查分配的内存 + return ptr; +} +``` + +**调试步骤**: +1. 在分配函数中设置断点 +2. 使用watchpoint监控指针变量 +3. 检查内存是否被正确释放 + +### 案例3:调试多线程问题 + +```cpp +void* threadFunction(void* arg) { + // 线程函数 + int* value = (int*)arg; + *value = 42; + return NULL; +} +``` + +**调试步骤**: +1. 在多个线程中设置断点 +2. 使用`thread apply all bt`查看所有线程状态 +3. 检查共享变量的访问 + +## 调试脚本 + +### GDB脚本示例 + +```gdb +# .gdbinit +# 自动加载符号 +file /path/to/library.so +set solib-search-path /path/to/symbols + +# 定义命令 +define print_stack + bt + info registers + x/20x $sp +end + +# 自动执行 +break main +run +``` + +### LLDB脚本示例 + +```python +# .lldbinit +# 定义命令 +def print_stack(debugger, command, result, dict): + """打印堆栈和寄存器""" + debugger.HandleCommand("bt") + debugger.HandleCommand("register read") + debugger.HandleCommand("memory read --format x --count 20 $sp") + +# 注册命令 +lldb.debugger.HandleCommand("command script add -f print_stack print_stack") +``` + +## 常见问题 + +### 1. 符号文件找不到 + +```bash +# 确保使用带符号的库文件 +# 设置符号搜索路径 +(gdb) set solib-search-path /path/to/symbols +``` + +### 2. 无法附加到进程 + +```bash +# 检查应用是否可调试 +adb shell getprop ro.debuggable + +# 使用root权限 +adb root +``` + +### 3. 断点不生效 + +```bash +# 确保代码已加载 +(gdb) info sharedlibrary + +# 检查断点位置是否正确 +(gdb) info breakpoints +``` + +## 最佳实践 + +1. **使用符号文件**: 始终使用带调试符号的库文件 +2. **记录调试过程**: 保存调试会话和关键信息 +3. **自动化脚本**: 编写脚本简化重复操作 +4. **版本匹配**: 确保调试器版本与目标匹配 +5. **安全考虑**: 生产环境禁用调试功能 + +## 相关链接 + +- [[README]] +- [[ADB高级命令]] +- [[Systrace_Perfetto全解读]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/09-调试与工具链/README.md b/docs/Obsidian笔记体系/Areas/09-调试与工具链/README.md index ac63e95..890c386 100644 --- a/docs/Obsidian笔记体系/Areas/09-调试与工具链/README.md +++ b/docs/Obsidian笔记体系/Areas/09-调试与工具链/README.md @@ -1 +1,160 @@ # 09-调试与工具链 + +## 概述 + +调试与工具链是Android Framework开发中不可或缺的技能。本目录系统性地整理了Android开发中的调试方法、工具使用和自定义工具开发。 + +## 目录结构 + +### 1. ADB高级命令 +- ADB常用命令详解 +- 系统服务调试 +- 日志分析技巧 +- 性能数据采集 + +### 2. GDB/LLDB调试Native +- Native代码调试方法 +- GDB/LLDB使用技巧 +- 断点与内存分析 +- 崩溃堆栈分析 + +### 3. Systrace/Perfetto全解读 +- 系统级性能分析 +- Trace文件解析 +- 性能瓶颈定位 +- 优化建议生成 + +### 4. 自定义调试工具开发 +- 调试工具设计思路 +- 工具开发实践 +- 工具集成方法 + +## 调试方法论 + +### 1. 问题定位流程 + +``` +问题现象 + ↓ +收集日志 + ↓ +分析堆栈 + ↓ +定位代码 + ↓ +复现问题 + ↓ +修复验证 +``` + +### 2. 调试原则 + +- **系统性思考**: 从整体到局部 +- **数据驱动**: 用数据说话,不要猜测 +- **工具辅助**: 善用各种调试工具 +- **持续学习**: 掌握新工具和方法 + +### 3. 日志策略 + +- **分级记录**: 使用合适的日志级别 +- **关键路径**: 在关键路径添加日志 +- **性能考虑**: 避免日志影响性能 +- **隐私保护**: 注意敏感信息脱敏 + +## 工具分类 + +### 官方工具 + +#### Android Studio +- **Debugger**: Java/Kotlin代码调试 +- **Profiler**: 性能分析 +- **Layout Inspector**: 布局分析 +- **Network Inspector**: 网络分析 + +#### ADB (Android Debug Bridge) +- 设备连接与管理 +- 日志查看与分析 +- 系统服务调试 +- 性能数据采集 + +#### Systrace/Perfetto +- 系统级性能分析 +- 帧率分析 +- CPU调度分析 +- 系统调用追踪 + +### 第三方工具 + +#### LeakCanary +- 内存泄漏检测 +- 自动分析泄漏路径 + +#### BlockCanary +- 主线程阻塞检测 +- ANR预警 + +#### Stetho +- Chrome DevTools集成 +- 网络请求查看 +- 数据库查看 + +### 自定义工具 + +- 根据项目需求定制 +- 集成到开发流程 +- 自动化测试与验证 + +## 调试场景 + +### 1. 崩溃调试 +- 收集崩溃堆栈 +- 分析崩溃原因 +- 复现与修复 + +### 2. 性能调试 +- 定位性能瓶颈 +- 分析耗时操作 +- 优化验证 + +### 3. 内存调试 +- 内存泄漏检测 +- 内存占用分析 +- GC分析 + +### 4. 网络调试 +- 请求响应分析 +- 网络性能优化 +- 错误排查 + +### 5. UI调试 +- 布局问题定位 +- 渲染性能分析 +- 动画调试 + +## 最佳实践 + +### 1. 建立调试环境 +- 配置开发环境 +- 准备测试设备 +- 设置日志收集 + +### 2. 使用版本控制 +- 记录调试过程 +- 保存关键日志 +- 文档化问题 + +### 3. 自动化测试 +- 单元测试 +- 集成测试 +- 性能测试 + +### 4. 持续监控 +- 线上监控 +- 性能指标 +- 异常告警 + +## 相关链接 + +- [[06-性能优化体系]] +- [[05-进程与线程通信]] +- [[MOCs/Android Framework知识体系图]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md b/docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md index 47c6169..7dc265c 100644 --- a/docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md +++ b/docs/Obsidian笔记体系/Areas/09-调试与工具链/Systrace_Perfetto全解读.md @@ -1 +1,419 @@ # Systrace/Perfetto全解读 + +## 概述 + +Systrace和Perfetto是Android系统级性能分析工具,可以追踪系统调用、CPU调度、渲染流程等,是性能优化的必备工具。 + +## Systrace基础 + +### Systrace简介 + +Systrace是Android 4.1引入的系统级追踪工具,可以记录系统调用、CPU调度、渲染等信息。 + +### 安装与使用 + +```bash +# Systrace位于Android SDK的platform-tools/systrace目录 +# 或使用Python脚本 +python systrace.py [options] [categories] + +# 基本用法 +python systrace.py -t 10 -o trace.html sched gfx view +``` + +### 常用参数 + +```bash +# -t: 追踪时间(秒) +python systrace.py -t 10 -o trace.html + +# -o: 输出文件 +python systrace.py -t 10 -o my_trace.html + +# -b: 缓冲区大小(KB) +python systrace.py -t 10 -b 32768 -o trace.html + +# -a: 指定应用包名 +python systrace.py -t 10 -a com.example.app -o trace.html + +# -k: 指定要追踪的函数(用逗号分隔) +python systrace.py -t 10 -k load_symbols,unload_symbols -o trace.html +``` + +### 追踪类别(Categories) + +```bash +# CPU调度 +sched + +# 图形渲染 +gfx + +# 视图系统 +view + +# 输入事件 +input + +# 磁盘I/O +disk + +# 内存 +mem + +# 活动管理器 +am + +# 窗口管理器 +wm + +# 数据库 +db + +# 网络 +network + +# 电源管理 +power + +# 全部类别 +-a +``` + +### 完整示例 + +```bash +# 追踪应用启动 +python systrace.py -t 5 -a com.example.app \ + -o startup_trace.html \ + sched freq idle am wm gfx view binder_driver hal dalvik camera input res + +# 追踪流畅度问题 +python systrace.py -t 10 \ + -o jank_trace.html \ + gfx view sched freq idle + +# 追踪内存问题 +python systrace.py -t 10 \ + -o memory_trace.html \ + sched freq idle mem +``` + +## Perfetto基础 + +### Perfetto简介 + +Perfetto是Google开发的下一代性能分析工具,从Android 9开始集成,功能更强大,支持更长的追踪时间。 + +### 使用Perfetto + +#### 1. 通过Android Studio + +1. 打开Android Studio +2. 连接设备 +3. 打开Profiler +4. 选择CPU Profiler +5. 点击"Record"开始录制 +6. 执行操作 +7. 停止录制,查看结果 + +#### 2. 通过命令行 + +```bash +# 使用perfetto命令行工具 +adb shell perfetto -c - --out /data/misc/perfetto-traces/trace + +# 或使用配置文件 +adb shell perfetto -c /data/local/tmp/config.pb -o /data/local/tmp/trace.pb +``` + +#### 3. 通过Web UI + +```bash +# 1. 录制trace +adb shell perfetto -c - --out /data/misc/perfetto-traces/trace + +# 2. 拉取trace文件 +adb pull /data/misc/perfetto-traces/trace trace.pb + +# 3. 在 https://ui.perfetto.dev/ 打开 +``` + +### Perfetto配置文件 + +```protobuf +# config.pb (文本格式) +buffers: { + size_kb: 63488 + fill_policy: DISCARD +} +buffers: { + size_kb: 2048 + fill_policy: DISCARD +} + +data_sources: { + config { + name: "android.surfaceflinger.frame" + } +} +data_sources: { + config { + name: "linux.ftrace" + ftrace_config { + ftrace_events: "sched/sched_switch" + ftrace_events: "sched/sched_waking" + ftrace_events: "power/suspend_resume" + ftrace_events: "power/cpu_frequency" + ftrace_events: "power/cpu_idle" + ftrace_events: "gfx/mali_gpu_total" + buffer_size_kb: 2048 + drain_period_ms: 250 + } + } +} + +duration_ms: 10000 +``` + +## Trace文件分析 + +### 1. 打开Trace文件 + +```bash +# Systrace HTML文件 +# 直接在浏览器中打开 trace.html + +# Perfetto文件 +# 在 https://ui.perfetto.dev/ 打开 +# 或使用Android Studio打开 +``` + +### 2. 关键指标 + +#### Frame信息 +- **绿色**: 正常帧(< 16.67ms) +- **黄色**: 轻微掉帧(16.67-33.33ms) +- **红色**: 严重掉帧(> 33.33ms) + +#### CPU信息 +- **CPU频率**: 查看CPU是否降频 +- **CPU使用率**: 查看CPU负载 +- **CPU调度**: 查看线程调度情况 + +#### 渲染信息 +- **VSYNC**: 垂直同步信号 +- **Choreographer**: 帧调度 +- **RenderThread**: 渲染线程 +- **GPU**: GPU渲染时间 + +### 3. 分析技巧 + +#### 查找卡顿 +1. 找到红色或黄色的Frame +2. 点击Frame查看详细信息 +3. 查看该时间段内的CPU活动 +4. 查找耗时操作 + +#### 分析启动时间 +1. 找到应用启动的起点 +2. 追踪到首帧渲染完成 +3. 分析各个阶段的耗时 +4. 识别瓶颈 + +#### 分析内存问题 +1. 查看内存分配事件 +2. 查找频繁的GC +3. 分析内存增长趋势 + +## 实战案例 + +### 案例1:分析应用启动 + +```bash +# 1. 录制启动trace +python systrace.py -t 5 -a com.example.app \ + -o startup.html \ + sched freq idle am wm gfx view + +# 2. 分析步骤 +# - 找到Application.onCreate开始时间 +# - 找到MainActivity.onCreate开始时间 +# - 找到首帧渲染完成时间 +# - 计算各阶段耗时 +``` + +**关键指标**: +- Application初始化时间 +- Activity创建时间 +- 布局inflate时间 +- 首帧渲染时间 + +### 案例2:分析流畅度问题 + +```bash +# 1. 录制流畅度trace +python systrace.py -t 10 \ + -o jank.html \ + gfx view sched freq idle + +# 2. 分析步骤 +# - 找到掉帧的Frame(红色/黄色) +# - 查看该Frame的耗时 +# - 分析主线程活动 +# - 查找阻塞操作 +``` + +**常见问题**: +- 主线程阻塞 +- 布局复杂 +- 过度绘制 +- 内存抖动 + +### 案例3:分析CPU使用率 + +```bash +# 1. 录制CPU trace +python systrace.py -t 10 \ + -o cpu.html \ + sched freq idle + +# 2. 分析步骤 +# - 查看CPU频率变化 +# - 查看CPU使用率 +# - 分析线程调度 +# - 查找CPU密集型操作 +``` + +## 高级技巧 + +### 1. 自定义Trace点 + +```java +// 在代码中添加自定义trace点 +import android.os.Trace; + +// 开始trace +Trace.beginSection("my_custom_section"); + +// 执行操作 +doSomething(); + +// 结束trace +Trace.endSection(); +``` + +### 2. 异步Trace + +```java +// 异步trace +Trace.beginAsyncSection("async_operation", cookie); +// 执行异步操作 +Trace.endAsyncSection("async_operation", cookie); +``` + +### 3. 计数器 + +```java +// 设置计数器 +Trace.setCounter("my_counter", value); +``` + +### 4. 使用ATrace命令 + +```bash +# 在shell中启用trace +adb shell setprop debug.atrace.tags.enableflags 0x1 + +# 开始trace +adb shell atrace -t 10 -b 32768 gfx view sched > trace.txt + +# 停止trace +adb shell atrace --async_stop +``` + +## Perfetto高级功能 + +### 1. 长时间追踪 + +```bash +# Perfetto支持更长的追踪时间 +adb shell perfetto -c - --out /data/misc/perfetto-traces/trace +# 可以追踪数小时 +``` + +### 2. 多数据源 + +Perfetto支持同时追踪多个数据源: +- CPU调度 +- 内存分配 +- 网络活动 +- 电源管理 +- 自定义事件 + +### 3. SQL查询 + +Perfetto支持SQL查询trace数据: + +```sql +-- 查询所有Frame信息 +SELECT * FROM slice WHERE name = 'Choreographer#doFrame'; + +-- 查询掉帧 +SELECT * FROM slice +WHERE name = 'Choreographer#doFrame' +AND dur > 16666667; + +-- 查询CPU使用率 +SELECT ts, cpu, value +FROM counter +WHERE name = 'cpu.freq'; +``` + +## 性能优化建议 + +### 1. 基于Trace的优化 + +1. **识别瓶颈**: 找到耗时最长的操作 +2. **分析原因**: 理解为什么耗时 +3. **制定方案**: 设计优化策略 +4. **验证效果**: 再次录制trace对比 + +### 2. 常见优化点 + +- **减少主线程工作**: 将耗时操作移到后台线程 +- **优化布局**: 减少布局层级和复杂度 +- **减少GC**: 避免内存抖动 +- **优化算法**: 使用更高效的算法 + +### 3. 持续监控 + +- 建立性能基线 +- 定期录制trace +- 设置性能告警 +- 跟踪性能趋势 + +## 工具对比 + +| 特性 | Systrace | Perfetto | +|------|----------|----------| +| 支持版本 | Android 4.1+ | Android 9+ | +| 追踪时间 | 较短 | 较长 | +| 数据源 | 有限 | 丰富 | +| 分析能力 | 基础 | 强大 | +| SQL查询 | 不支持 | 支持 | +| Web UI | 基础 | 强大 | + +## 最佳实践 + +1. **明确目标**: 在录制前明确要分析的问题 +2. **合适时长**: 选择适当的追踪时间 +3. **关键类别**: 只追踪相关的类别 +4. **多次录制**: 多次录制确保结果一致 +5. **对比分析**: 优化前后对比分析 + +## 相关链接 + +- [[README]] +- [[06-性能优化体系/流畅度(Choreographer+VSYNC)]] +- [[06-性能优化体系/启动优化方法论]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Areas/09-调试与工具链/自定义调试工具开发.md b/docs/Obsidian笔记体系/Areas/09-调试与工具链/自定义调试工具开发.md index 5cfadcf..ea5ffc2 100644 --- a/docs/Obsidian笔记体系/Areas/09-调试与工具链/自定义调试工具开发.md +++ b/docs/Obsidian笔记体系/Areas/09-调试与工具链/自定义调试工具开发.md @@ -1 +1,538 @@ # 自定义调试工具开发 + +## 概述 + +在Android开发中,有时需要开发自定义的调试工具来满足特定需求。本文档介绍如何设计和开发自定义调试工具。 + +## 工具设计原则 + +### 1. 明确需求 + +在开发工具前,需要明确: +- **解决什么问题**: 工具要解决的具体问题 +- **目标用户**: 谁将使用这个工具 +- **使用场景**: 在什么情况下使用 +- **性能要求**: 对性能的影响要求 + +### 2. 设计原则 + +- **易用性**: 界面简洁,操作简单 +- **可靠性**: 稳定可靠,不影响应用运行 +- **可扩展性**: 便于后续扩展功能 +- **性能**: 对应用性能影响最小 + +### 3. 技术选型 + +- **语言**: Java/Kotlin/C++ +- **框架**: 根据需求选择 +- **UI**: 命令行/图形界面/Web界面 +- **部署**: 独立应用/集成到应用/插件 + +## 工具类型 + +### 1. 性能监控工具 + +#### 功能需求 +- CPU使用率监控 +- 内存使用监控 +- 帧率监控 +- 网络请求监控 + +#### 实现示例 + +```java +public class PerformanceMonitor { + private static PerformanceMonitor sInstance; + private Handler mHandler; + private boolean mMonitoring = false; + + public static PerformanceMonitor getInstance() { + if (sInstance == null) { + sInstance = new PerformanceMonitor(); + } + return sInstance; + } + + public void startMonitoring() { + if (mMonitoring) { + return; + } + mMonitoring = true; + mHandler = new Handler(Looper.getMainLooper()); + mHandler.post(mMonitorRunnable); + } + + public void stopMonitoring() { + mMonitoring = false; + if (mHandler != null) { + mHandler.removeCallbacks(mMonitorRunnable); + } + } + + private Runnable mMonitorRunnable = new Runnable() { + @Override + public void run() { + if (!mMonitoring) { + return; + } + + // 收集性能数据 + collectPerformanceData(); + + // 1秒后再次执行 + mHandler.postDelayed(this, 1000); + } + }; + + private void collectPerformanceData() { + // CPU使用率 + float cpuUsage = getCpuUsage(); + + // 内存使用 + long memoryUsage = getMemoryUsage(); + + // 帧率 + float fps = getFPS(); + + // 记录数据 + Log.d("Performance", String.format( + "CPU: %.2f%%, Memory: %dMB, FPS: %.2f", + cpuUsage, memoryUsage / 1024 / 1024, fps + )); + } + + private float getCpuUsage() { + // 实现CPU使用率计算 + // 通过/proc/stat计算 + return 0.0f; + } + + private long getMemoryUsage() { + Runtime runtime = Runtime.getRuntime(); + return runtime.totalMemory() - runtime.freeMemory(); + } + + private float getFPS() { + // 使用Choreographer计算FPS + return 0.0f; + } +} +``` + +### 2. 日志收集工具 + +#### 功能需求 +- 自动收集日志 +- 日志分类存储 +- 日志上传 +- 日志分析 + +#### 实现示例 + +```java +public class LogCollector { + private static final String LOG_DIR = "logs"; + private File mLogDir; + private File mCurrentLogFile; + + public LogCollector(Context context) { + mLogDir = new File(context.getFilesDir(), LOG_DIR); + if (!mLogDir.exists()) { + mLogDir.mkdirs(); + } + } + + public void startCollecting() { + // 创建新的日志文件 + String fileName = "log_" + System.currentTimeMillis() + ".txt"; + mCurrentLogFile = new File(mLogDir, fileName); + + // 启动日志收集线程 + new Thread(() -> { + collectLogs(); + }).start(); + } + + private void collectLogs() { + try { + Process process = Runtime.getRuntime().exec("logcat"); + BufferedReader reader = new BufferedReader( + new InputStreamReader(process.getInputStream()) + ); + + FileWriter writer = new FileWriter(mCurrentLogFile); + String line; + while ((line = reader.readLine()) != null) { + // 过滤和格式化日志 + if (shouldCollect(line)) { + writer.write(line + "\n"); + writer.flush(); + } + } + + writer.close(); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private boolean shouldCollect(String line) { + // 实现日志过滤逻辑 + return line.contains("MyApp"); + } + + public void uploadLogs(String url) { + // 实现日志上传逻辑 + // 可以使用OkHttp等网络库 + } +} +``` + +### 3. 内存分析工具 + +#### 功能需求 +- 内存快照 +- 内存泄漏检测 +- 内存使用分析 +- 内存报告生成 + +#### 实现示例 + +```java +public class MemoryAnalyzer { + private ActivityManager mActivityManager; + + public MemoryAnalyzer(Context context) { + mActivityManager = (ActivityManager) + context.getSystemService(Context.ACTIVITY_SERVICE); + } + + public MemoryInfo getMemoryInfo() { + ActivityManager.MemoryInfo memInfo = + new ActivityManager.MemoryInfo(); + mActivityManager.getMemoryInfo(memInfo); + + return new MemoryInfo( + memInfo.totalMem, + memInfo.availMem, + memInfo.threshold, + memInfo.lowMemory + ); + } + + public void dumpHeap(String fileName) { + try { + Debug.dumpHprofData(fileName); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public void analyzeMemoryLeak() { + // 实现内存泄漏检测逻辑 + // 可以集成LeakCanary + } + + public static class MemoryInfo { + public long totalMem; + public long availMem; + public long threshold; + public boolean lowMemory; + + public MemoryInfo(long total, long avail, + long threshold, boolean low) { + this.totalMem = total; + this.availMem = avail; + this.threshold = threshold; + this.lowMemory = low; + } + } +} +``` + +### 4. 网络监控工具 + +#### 功能需求 +- 网络请求拦截 +- 请求响应记录 +- 网络性能分析 +- 请求重放 + +#### 实现示例 + +```java +public class NetworkMonitor { + private List mRequests = new ArrayList<>(); + private boolean mMonitoring = false; + + public void startMonitoring() { + mMonitoring = true; + // 使用OkHttp Interceptor拦截请求 + } + + public void stopMonitoring() { + mMonitoring = false; + } + + public void addRequest(NetworkRequest request) { + if (mMonitoring) { + mRequests.add(request); + } + } + + public List getRequests() { + return new ArrayList<>(mRequests); + } + + public void exportRequests(String fileName) { + // 导出请求记录 + try { + FileWriter writer = new FileWriter(fileName); + for (NetworkRequest request : mRequests) { + writer.write(request.toString() + "\n"); + } + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static class NetworkRequest { + public String url; + public String method; + public Map headers; + public String requestBody; + public String responseBody; + public long duration; + public int statusCode; + } +} +``` + +## 工具集成方式 + +### 1. 独立应用 + +```java +// 作为独立的调试应用 +public class DebugApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + // 初始化调试工具 + DebugTools.init(this); + } +} +``` + +**优点**: +- 不影响主应用 +- 可以独立更新 +- 便于分发 + +**缺点**: +- 需要单独安装 +- 可能无法访问主应用数据 + +### 2. 集成到应用 + +```java +// 在主应用中集成 +public class MainApplication extends Application { + @Override + public void onCreate() { + super.onCreate(); + + if (BuildConfig.DEBUG) { + // 只在Debug版本启用 + DebugTools.init(this); + } + } +} +``` + +**优点**: +- 直接访问应用数据 +- 无需单独安装 +- 集成度高 + +**缺点**: +- 可能影响应用性能 +- 需要控制发布版本 + +### 3. 插件化 + +```java +// 使用插件机制 +public class DebugPlugin { + public void load(Context context) { + // 动态加载调试功能 + } + + public void unload() { + // 卸载调试功能 + } +} +``` + +**优点**: +- 灵活加载/卸载 +- 不影响主应用 +- 便于扩展 + +**缺点**: +- 实现复杂 +- 需要插件框架支持 + +## UI设计 + +### 1. 命令行界面 + +```java +public class DebugCLI { + public void start() { + Scanner scanner = new Scanner(System.in); + while (true) { + System.out.print("Debug> "); + String command = scanner.nextLine(); + executeCommand(command); + } + } + + private void executeCommand(String command) { + String[] parts = command.split(" "); + String cmd = parts[0]; + + switch (cmd) { + case "memory": + showMemoryInfo(); + break; + case "cpu": + showCpuInfo(); + break; + case "fps": + showFPS(); + break; + case "help": + showHelp(); + break; + default: + System.out.println("Unknown command: " + cmd); + } + } +} +``` + +### 2. 图形界面 + +```java +// 使用Android原生UI +public class DebugActivity extends AppCompatActivity { + private TextView mMemoryText; + private TextView mCpuText; + private TextView mFpsText; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_debug); + + mMemoryText = findViewById(R.id.memory_text); + mCpuText = findViewById(R.id.cpu_text); + mFpsText = findViewById(R.id.fps_text); + + startMonitoring(); + } + + private void startMonitoring() { + Handler handler = new Handler(); + handler.post(new Runnable() { + @Override + public void run() { + updateUI(); + handler.postDelayed(this, 1000); + } + }); + } + + private void updateUI() { + // 更新UI显示 + mMemoryText.setText(getMemoryInfo()); + mCpuText.setText(getCpuInfo()); + mFpsText.setText(getFpsInfo()); + } +} +``` + +### 3. Web界面 + +```java +// 使用WebView或HTTP服务器 +public class DebugWebServer { + private HttpServer mServer; + + public void start(int port) { + try { + mServer = HttpServer.create(new InetSocketAddress(port), 0); + mServer.createContext("/", new DebugHandler()); + mServer.setExecutor(null); + mServer.start(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private class DebugHandler implements HttpHandler { + @Override + public void handle(HttpExchange exchange) throws IOException { + String response = generateResponse(); + exchange.sendResponseHeaders(200, response.length()); + OutputStream os = exchange.getResponseBody(); + os.write(response.getBytes()); + os.close(); + } + } +} +``` + +## 工具发布 + +### 1. 版本管理 + +```gradle +// build.gradle +android { + defaultConfig { + versionCode 1 + versionName "1.0.0" + } +} +``` + +### 2. 文档编写 + +- **使用说明**: 如何安装和使用 +- **功能说明**: 功能介绍 +- **常见问题**: FAQ +- **更新日志**: 版本更新记录 + +### 3. 分发方式 + +- **内部使用**: 通过内部渠道分发 +- **GitHub**: 开源发布 +- **应用商店**: 发布到应用商店 + +## 最佳实践 + +1. **性能优先**: 确保工具不影响应用性能 +2. **易于使用**: 界面简洁,操作直观 +3. **稳定可靠**: 充分测试,确保稳定 +4. **文档完善**: 提供详细的使用文档 +5. **持续维护**: 根据反馈持续改进 + +## 相关链接 + +- [[README]] +- [[ADB高级命令]] +- [[06-性能优化体系]] \ No newline at end of file diff --git a/docs/Obsidian笔记体系/Resources/工具/效率工具推荐/README.md b/docs/Obsidian笔记体系/Resources/工具/效率工具推荐/README.md new file mode 100644 index 0000000..6a2d71d --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/效率工具推荐/README.md @@ -0,0 +1,440 @@ +# 效率工具推荐 + +## 概述 + +本文档收集了Android Framework开发中常用的效率工具,包括开发工具、调试工具、性能分析工具等。 + +## 开发工具 + +### 1. Android Studio + +**简介**: Google官方Android开发IDE + +**主要功能**: +- 代码编辑与智能提示 +- 调试器(Java/Kotlin/Native) +- Profiler性能分析 +- Layout Inspector布局分析 +- Network Inspector网络分析 + +**下载地址**: https://developer.android.com/studio + +**推荐理由**: +- 官方支持,功能完善 +- 集成多种调试工具 +- 持续更新 + +### 2. IntelliJ IDEA + +**简介**: JetBrains开发的Java IDE + +**主要功能**: +- 强大的代码分析 +- 丰富的插件生态 +- 优秀的重构工具 + +**适用场景**: +- 大型项目开发 +- 需要深度代码分析 + +**下载地址**: https://www.jetbrains.com/idea/ + +### 3. VS Code + +**简介**: 轻量级代码编辑器 + +**主要功能**: +- 轻量快速 +- 丰富的扩展 +- 多语言支持 + +**适用场景**: +- 快速编辑 +- 多语言项目 +- 脚本编写 + +**下载地址**: https://code.visualstudio.com/ + +## 调试工具 + +### 1. LeakCanary + +**简介**: Square开源的内存泄漏检测工具 + +**主要功能**: +- 自动检测内存泄漏 +- 可视化泄漏路径 +- 集成简单 + +**使用方式**: +```gradle +dependencies { + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12' +} +``` + +**推荐理由**: +- 自动检测,无需手动操作 +- 提供详细的泄漏信息 +- 社区活跃 + +**GitHub**: https://github.com/square/leakcanary + +### 2. BlockCanary + +**简介**: 主线程阻塞检测工具 + +**主要功能**: +- 检测主线程阻塞 +- ANR预警 +- 性能监控 + +**使用方式**: +```gradle +dependencies { + debugImplementation 'com.github.markzhai:blockcanary-android:1.5.0' +} +``` + +**推荐理由**: +- 及时发现性能问题 +- 提供详细的阻塞信息 + +**GitHub**: https://github.com/markzhai/AndroidPerformanceMonitor + +### 3. Stetho + +**简介**: Facebook开发的Android调试工具 + +**主要功能**: +- Chrome DevTools集成 +- 网络请求查看 +- 数据库查看 +- SharedPreferences查看 + +**使用方式**: +```gradle +dependencies { + debugImplementation 'com.facebook.stetho:stetho:1.6.0' +} +``` + +**推荐理由**: +- 使用Chrome DevTools,界面友好 +- 功能丰富 + +**GitHub**: https://github.com/facebook/stetho + +## 性能分析工具 + +### 1. Systrace/Perfetto + +**简介**: Google官方系统级性能分析工具 + +**主要功能**: +- 系统调用追踪 +- CPU调度分析 +- 渲染流程分析 +- 帧率分析 + +**使用方式**: +```bash +python systrace.py -t 10 -o trace.html sched gfx view +``` + +**推荐理由**: +- 官方工具,功能强大 +- 系统级分析能力 + +**文档**: [[09-调试与工具链/Systrace_Perfetto全解读]] + +### 2. Android Profiler + +**简介**: Android Studio内置性能分析工具 + +**主要功能**: +- CPU分析 +- 内存分析 +- 网络分析 +- 功耗分析 + +**推荐理由**: +- 集成在IDE中,使用方便 +- 实时监控 + +### 3. Battery Historian + +**简介**: Google官方功耗分析工具 + +**主要功能**: +- 电量消耗分析 +- Wake Lock分析 +- 网络使用分析 + +**使用方式**: +```bash +go get -u github.com/google/battery-historian +``` + +**推荐理由**: +- 官方工具 +- 详细的功耗分析 + +**GitHub**: https://github.com/google/battery-historian + +## 代码质量工具 + +### 1. Lint + +**简介**: Android官方代码检查工具 + +**主要功能**: +- 代码规范检查 +- 性能问题检测 +- 安全问题检测 + +**使用方式**: +```bash +./gradlew lint +``` + +**推荐理由**: +- 官方工具 +- 集成在构建流程中 + +### 2. FindBugs/SpotBugs + +**简介**: Java代码静态分析工具 + +**主要功能**: +- Bug检测 +- 代码质量分析 + +**推荐理由**: +- 检测能力强 +- 社区活跃 + +### 3. SonarQube + +**简介**: 代码质量管理平台 + +**主要功能**: +- 代码质量分析 +- 技术债务管理 +- 持续集成 + +**推荐理由**: +- 功能全面 +- 支持多种语言 + +## 版本控制工具 + +### 1. Git + +**简介**: 分布式版本控制系统 + +**主要功能**: +- 版本管理 +- 分支管理 +- 代码合并 + +**推荐理由**: +- 行业标准 +- 功能强大 + +**文档**: [[Obsidian/git]] + +### 2. SourceTree + +**简介**: Git图形化客户端 + +**主要功能**: +- 可视化Git操作 +- 分支管理 +- 代码对比 + +**推荐理由**: +- 界面友好 +- 操作直观 + +### 3. GitKraken + +**简介**: 现代化的Git客户端 + +**主要功能**: +- 可视化提交历史 +- 分支管理 +- 代码对比 + +**推荐理由**: +- 界面美观 +- 功能丰富 + +## 文档工具 + +### 1. Markdown编辑器 + +#### Typora +- 所见即所得 +- 支持数学公式 +- 界面简洁 + +#### Obsidian +- 知识管理 +- 双向链接 +- 插件丰富 + +#### VS Code + Markdown插件 +- 轻量级 +- 扩展丰富 + +### 2. 文档生成工具 + +#### MkDocs +- 基于Markdown +- 主题丰富 +- 部署简单 + +#### Doxygen +- 代码文档生成 +- 支持多种语言 + +## 效率提升工具 + +### 1. Alfred (macOS) + +**简介**: 效率启动器 + +**主要功能**: +- 快速启动应用 +- 文件搜索 +- 自定义工作流 + +**推荐理由**: +- 大幅提升操作效率 +- 可定制性强 + +### 2. Everything (Windows) + +**简介**: 文件搜索工具 + +**主要功能**: +- 极速文件搜索 +- 支持正则表达式 + +**推荐理由**: +- 搜索速度快 +- 资源占用低 + +### 3. Ditto (Windows) + +**简介**: 剪贴板管理工具 + +**主要功能**: +- 剪贴板历史 +- 多剪贴板管理 + +**推荐理由**: +- 提高复制粘贴效率 + +## 网络工具 + +### 1. Charles + +**简介**: HTTP代理工具 + +**主要功能**: +- 网络请求拦截 +- 请求修改 +- 性能分析 + +**推荐理由**: +- 功能强大 +- 界面友好 + +### 2. Postman + +**简介**: API测试工具 + +**主要功能**: +- API测试 +- 请求集合管理 +- 自动化测试 + +**推荐理由**: +- 功能全面 +- 团队协作 + +### 3. Wireshark + +**简介**: 网络协议分析工具 + +**主要功能**: +- 网络包捕获 +- 协议分析 +- 流量分析 + +**推荐理由**: +- 功能强大 +- 专业级工具 + +## 系统工具 + +### 1. iTerm2 (macOS) + +**简介**: 终端替代工具 + +**主要功能**: +- 分屏 +- 标签页 +- 主题定制 + +**推荐理由**: +- 功能强大 +- 可定制性强 + +### 2. Windows Terminal + +**简介**: Windows现代终端 + +**主要功能**: +- 多标签页 +- 主题定制 +- 集成PowerShell/CMD + +**推荐理由**: +- 官方支持 +- 现代化界面 + +### 3. tmux + +**简介**: 终端复用器 + +**主要功能**: +- 会话管理 +- 窗口分割 +- 远程会话保持 + +**推荐理由**: +- 提高终端使用效率 +- 支持远程开发 + +## 推荐配置 + +### Android开发环境 + +1. **IDE**: Android Studio +2. **版本控制**: Git + SourceTree +3. **调试工具**: LeakCanary + BlockCanary + Stetho +4. **性能分析**: Android Profiler + Systrace +5. **文档**: Obsidian + MkDocs + +### 效率工具组合 + +1. **macOS**: Alfred + iTerm2 + tmux +2. **Windows**: Everything + Ditto + Windows Terminal + +## 相关链接 + +- [[09-调试与工具链]] +- [[脚本库/README]] diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/README.md b/docs/Obsidian笔记体系/Resources/工具/脚本库/README.md new file mode 100644 index 0000000..6545d4b --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/README.md @@ -0,0 +1,565 @@ +# 脚本库 + +## 概述 + +本文档收集了Android开发中常用的脚本,包括构建脚本、自动化脚本、工具脚本等。 + +## 构建脚本 + +### 1. Gradle构建脚本 + +#### 通用构建配置 + +```gradle +// build.gradle (Project) +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:7.4.2' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} +``` + +#### 应用构建配置 + +```gradle +// build.gradle (App) +android { + compileSdkVersion 33 + + defaultConfig { + applicationId "com.example.app" + minSdkVersion 21 + targetSdkVersion 33 + versionCode 1 + versionName "1.0.0" + } + + buildTypes { + release { + minifyEnabled true + shrinkResources true + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), + 'proguard-rules.pro' + } + } +} +``` + +### 2. 构建优化脚本 + +```gradle +// 并行构建 +org.gradle.parallel=true +org.gradle.caching=true +org.gradle.configureondemand=true + +// 增加内存 +org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=512m +``` + +## 自动化脚本 + +### 1. 批量安装APK + +```bash +#!/bin/bash +# install_apks.sh +# 批量安装当前目录下的所有APK + +for apk in *.apk; do + if [ -f "$apk" ]; then + echo "Installing $apk..." + adb install -r "$apk" + if [ $? -eq 0 ]; then + echo "Successfully installed $apk" + else + echo "Failed to install $apk" + fi + fi +done +``` + +### 2. 清理并重启 + +```bash +#!/bin/bash +# clean_and_reboot.sh +# 清理日志并重启设备 + +echo "Clearing logcat..." +adb logcat -c + +echo "Clearing app data..." +adb shell pm clear com.example.app + +echo "Rebooting device..." +adb reboot + +echo "Waiting for device..." +adb wait-for-device + +echo "Device is ready!" +``` + +### 3. 性能数据采集 + +```bash +#!/bin/bash +# collect_performance.sh +# 采集性能数据 + +OUTPUT_DIR="performance_data_$(date +%Y%m%d_%H%M%S)" +mkdir -p "$OUTPUT_DIR" + +echo "Collecting CPU info..." +adb shell top -n 1 > "$OUTPUT_DIR/cpu.txt" + +echo "Collecting memory info..." +adb shell dumpsys meminfo > "$OUTPUT_DIR/meminfo.txt" + +echo "Collecting battery info..." +adb shell dumpsys batterystats > "$OUTPUT_DIR/batterystats.txt" + +echo "Collecting network stats..." +adb shell dumpsys netstats > "$OUTPUT_DIR/netstats.txt" + +echo "Data collected in $OUTPUT_DIR" +``` + +### 4. 日志收集脚本 + +```bash +#!/bin/bash +# collect_logs.sh +# 收集并过滤日志 + +PACKAGE_NAME="com.example.app" +OUTPUT_FILE="logs_$(date +%Y%m%d_%H%M%S).txt" + +echo "Collecting logs for $PACKAGE_NAME..." +adb logcat | grep "$PACKAGE_NAME" > "$OUTPUT_FILE" & +LOGCAT_PID=$! + +# 运行30秒 +sleep 30 + +# 停止日志收集 +kill $LOGCAT_PID + +echo "Logs saved to $OUTPUT_FILE" +``` + +## ADB工具脚本 + +### 1. 设备管理脚本 + +```bash +#!/bin/bash +# device_manager.sh +# 设备管理工具 + +function list_devices() { + echo "Connected devices:" + adb devices -l +} + +function get_device_info() { + echo "Device Info:" + echo "Model: $(adb shell getprop ro.product.model)" + echo "Android Version: $(adb shell getprop ro.build.version.release)" + echo "SDK Version: $(adb shell getprop ro.build.version.sdk)" + echo "Manufacturer: $(adb shell getprop ro.product.manufacturer)" +} + +function install_apk() { + if [ -z "$1" ]; then + echo "Usage: install_apk " + return 1 + fi + adb install -r "$1" +} + +case "$1" in + list) + list_devices + ;; + info) + get_device_info + ;; + install) + install_apk "$2" + ;; + *) + echo "Usage: $0 {list|info|install}" + exit 1 + ;; +esac +``` + +### 2. 应用管理脚本 + +```bash +#!/bin/bash +# app_manager.sh +# 应用管理工具 + +PACKAGE_NAME="$2" + +function stop_app() { + adb shell am force-stop "$PACKAGE_NAME" + echo "Stopped $PACKAGE_NAME" +} + +function clear_data() { + adb shell pm clear "$PACKAGE_NAME" + echo "Cleared data for $PACKAGE_NAME" +} + +function uninstall_app() { + adb uninstall "$PACKAGE_NAME" + echo "Uninstalled $PACKAGE_NAME" +} + +function get_app_info() { + adb shell dumpsys package "$PACKAGE_NAME" | grep -E "versionName|versionCode" +} + +case "$1" in + stop) + stop_app + ;; + clear) + clear_data + ;; + uninstall) + uninstall_app + ;; + info) + get_app_info + ;; + *) + echo "Usage: $0 {stop|clear|uninstall|info} " + exit 1 + ;; +esac +``` + +## Python工具脚本 + +### 1. APK分析脚本 + +```python +#!/usr/bin/env python3 +# apk_analyzer.py +# APK信息分析工具 + +import subprocess +import sys +import re + +def get_apk_info(apk_path): + """获取APK信息""" + try: + # 使用aapt获取信息 + result = subprocess.run( + ['aapt', 'dump', 'badging', apk_path], + capture_output=True, + text=True + ) + + if result.returncode != 0: + print(f"Error: {result.stderr}") + return None + + info = {} + for line in result.stdout.split('\n'): + if 'package:' in line: + # 解析包名和版本 + package_match = re.search(r"name='([^']+)'", line) + version_match = re.search(r"versionCode='(\d+)'", line) + version_name_match = re.search(r"versionName='([^']+)'", line) + + if package_match: + info['package'] = package_match.group(1) + if version_match: + info['version_code'] = version_match.group(1) + if version_name_match: + info['version_name'] = version_name_match.group(1) + + if 'application-label:' in line: + label_match = re.search(r"label='([^']+)'", line) + if label_match: + info['label'] = label_match.group(1) + + return info + except Exception as e: + print(f"Error: {e}") + return None + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: python apk_analyzer.py ") + sys.exit(1) + + apk_path = sys.argv[1] + info = get_apk_info(apk_path) + + if info: + print("APK Information:") + for key, value in info.items(): + print(f" {key}: {value}") +``` + +### 2. 日志分析脚本 + +```python +#!/usr/bin/env python3 +# log_analyzer.py +# 日志分析工具 + +import re +import sys +from collections import Counter + +def analyze_logs(log_file): + """分析日志文件""" + errors = [] + warnings = [] + patterns = { + 'crash': r'FATAL|crash|exception', + 'anr': r'ANR|Application Not Responding', + 'oom': r'OutOfMemory|OOM', + } + + with open(log_file, 'r', encoding='utf-8', errors='ignore') as f: + for line_num, line in enumerate(f, 1): + # 检查错误 + if 'E/' in line or 'ERROR' in line.upper(): + errors.append((line_num, line.strip())) + + # 检查警告 + if 'W/' in line or 'WARN' in line.upper(): + warnings.append((line_num, line.strip())) + + # 检查特定模式 + for pattern_name, pattern in patterns.items(): + if re.search(pattern, line, re.IGNORECASE): + print(f"[{pattern_name.upper()}] Line {line_num}: {line.strip()}") + + print(f"\nSummary:") + print(f" Errors: {len(errors)}") + print(f" Warnings: {len(warnings)}") + + if errors: + print(f"\nFirst 10 errors:") + for line_num, line in errors[:10]: + print(f" Line {line_num}: {line}") + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: python log_analyzer.py ") + sys.exit(1) + + log_file = sys.argv[1] + analyze_logs(log_file) +``` + +## Git工具脚本 + +### 1. 批量提交脚本 + +```bash +#!/bin/bash +# batch_commit.sh +# 批量提交更改 + +COMMIT_MESSAGE="$1" + +if [ -z "$COMMIT_MESSAGE" ]; then + echo "Usage: batch_commit.sh " + exit 1 +fi + +# 添加所有更改 +git add . + +# 提交 +git commit -m "$COMMIT_MESSAGE" + +# 推送到远程 +read -p "Push to remote? (y/n) " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + git push +fi +``` + +### 2. 分支清理脚本 + +```bash +#!/bin/bash +# clean_branches.sh +# 清理已合并的分支 + +# 更新远程分支信息 +git fetch --prune + +# 切换到main分支 +git checkout main +git pull + +# 删除已合并的本地分支 +git branch --merged | grep -v "\*\|main\|master" | xargs -n 1 git branch -d + +# 删除远程已合并的分支 +git remote prune origin + +echo "Branches cleaned!" +``` + +## 性能测试脚本 + +### 1. 启动时间测试 + +```bash +#!/bin/bash +# test_startup_time.sh +# 测试应用启动时间 + +PACKAGE_NAME="com.example.app" +MAIN_ACTIVITY="com.example.app/.MainActivity" +ITERATIONS=10 + +echo "Testing startup time for $PACKAGE_NAME" +echo "Iterations: $ITERATIONS" +echo "" + +total_time=0 + +for i in $(seq 1 $ITERATIONS); do + # 停止应用 + adb shell am force-stop "$PACKAGE_NAME" + sleep 1 + + # 启动应用并测量时间 + result=$(adb shell am start -W -n "$MAIN_ACTIVITY" | grep "TotalTime") + time=$(echo "$result" | awk '{print $2}') + + echo "Iteration $i: ${time}ms" + total_time=$((total_time + time)) + + sleep 2 +done + +average=$((total_time / ITERATIONS)) +echo "" +echo "Average startup time: ${average}ms" +``` + +### 2. 内存监控脚本 + +```bash +#!/bin/bash +# monitor_memory.sh +# 监控应用内存使用 + +PACKAGE_NAME="$1" +INTERVAL=5 + +if [ -z "$PACKAGE_NAME" ]; then + echo "Usage: monitor_memory.sh [interval_seconds]" + exit 1 +fi + +if [ -n "$2" ]; then + INTERVAL="$2" +fi + +echo "Monitoring memory for $PACKAGE_NAME (interval: ${INTERVAL}s)" +echo "Press Ctrl+C to stop" +echo "" + +while true; do + timestamp=$(date '+%Y-%m-%d %H:%M:%S') + meminfo=$(adb shell dumpsys meminfo "$PACKAGE_NAME" | grep "TOTAL") + + if [ -n "$meminfo" ]; then + pss=$(echo "$meminfo" | awk '{print $2}') + echo "[$timestamp] PSS: ${pss}KB" + fi + + sleep "$INTERVAL" +done +``` + +## 部署脚本 + +### 1. 自动部署脚本 + +```bash +#!/bin/bash +# deploy.sh +# 自动构建和部署 + +echo "Building APK..." +./gradlew assembleRelease + +if [ $? -ne 0 ]; then + echo "Build failed!" + exit 1 +fi + +APK_PATH="app/build/outputs/apk/release/app-release.apk" + +if [ ! -f "$APK_PATH" ]; then + echo "APK not found: $APK_PATH" + exit 1 +fi + +echo "Installing APK..." +adb install -r "$APK_PATH" + +if [ $? -eq 0 ]; then + echo "Deployment successful!" +else + echo "Deployment failed!" + exit 1 +fi +``` + +## 使用说明 + +### 脚本执行权限 + +```bash +# 添加执行权限 +chmod +x script.sh + +# 执行脚本 +./script.sh +``` + +### 脚本路径 + +建议将常用脚本放在 `~/scripts/` 目录下,并添加到PATH: + +```bash +# 添加到 ~/.bashrc 或 ~/.zshrc +export PATH="$HOME/scripts:$PATH" +``` + +## 相关链接 + +- [[效率工具推荐/README]] +- [[09-调试与工具链/ADB高级命令]] diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/collect_logs.sh b/docs/Obsidian笔记体系/Resources/工具/脚本库/collect_logs.sh new file mode 100644 index 0000000..3fd9206 --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/collect_logs.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# collect_logs.sh +# 收集并过滤日志 + +PACKAGE_NAME="${1:-com.example.app}" +DURATION="${2:-30}" +OUTPUT_FILE="logs_${PACKAGE_NAME}_$(date +%Y%m%d_%H%M%S).txt" + +echo "Collecting logs for package: $PACKAGE_NAME" +echo "Duration: ${DURATION} seconds" +echo "Output file: $OUTPUT_FILE" +echo "Press Ctrl+C to stop early" +echo "" + +# 清空日志缓冲区 +adb logcat -c + +# 开始收集日志 +adb logcat | grep --line-buffered "$PACKAGE_NAME" > "$OUTPUT_FILE" & +LOGCAT_PID=$! + +# 等待指定时间 +sleep "$DURATION" + +# 停止日志收集 +kill $LOGCAT_PID 2>/dev/null +wait $LOGCAT_PID 2>/dev/null + +# 统计日志行数 +LINE_COUNT=$(wc -l < "$OUTPUT_FILE" 2>/dev/null || echo "0") + +echo "" +echo "Log collection completed!" +echo " File: $OUTPUT_FILE" +echo " Lines: $LINE_COUNT" + +# 显示最后几行 +if [ "$LINE_COUNT" -gt 0 ]; then + echo "" + echo "Last 10 lines:" + tail -n 10 "$OUTPUT_FILE" +fi diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/install_apks.sh b/docs/Obsidian笔记体系/Resources/工具/脚本库/install_apks.sh new file mode 100644 index 0000000..6fbf13a --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/install_apks.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# install_apks.sh +# 批量安装当前目录下的所有APK + +echo "Searching for APK files in current directory..." + +APK_COUNT=0 +SUCCESS_COUNT=0 +FAIL_COUNT=0 + +for apk in *.apk; do + if [ -f "$apk" ]; then + APK_COUNT=$((APK_COUNT + 1)) + echo "" + echo "[$APK_COUNT] Installing $apk..." + + adb install -r "$apk" + + if [ $? -eq 0 ]; then + echo "✓ Successfully installed $apk" + SUCCESS_COUNT=$((SUCCESS_COUNT + 1)) + else + echo "✗ Failed to install $apk" + FAIL_COUNT=$((FAIL_COUNT + 1)) + fi + fi +done + +echo "" +echo "=========================================" +echo "Summary:" +echo " Total APKs: $APK_COUNT" +echo " Success: $SUCCESS_COUNT" +echo " Failed: $FAIL_COUNT" +echo "=========================================" diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/log_analyzer.py b/docs/Obsidian笔记体系/Resources/工具/脚本库/log_analyzer.py new file mode 100644 index 0000000..b2a474c --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/log_analyzer.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# log_analyzer.py +# 日志分析工具 + +import re +import sys +from collections import Counter +from datetime import datetime + +def analyze_logs(log_file): + """分析日志文件""" + errors = [] + warnings = [] + patterns = { + 'crash': r'FATAL|crash|exception', + 'anr': r'ANR|Application Not Responding', + 'oom': r'OutOfMemory|OOM', + 'nullpointer': r'NullPointerException', + 'illegalstate': r'IllegalStateException', + } + + pattern_matches = {key: [] for key in patterns.keys()} + + print(f"Analyzing log file: {log_file}") + print("=" * 60) + + try: + with open(log_file, 'r', encoding='utf-8', errors='ignore') as f: + for line_num, line in enumerate(f, 1): + # 检查错误 + if 'E/' in line or 'ERROR' in line.upper(): + errors.append((line_num, line.strip())) + + # 检查警告 + if 'W/' in line or 'WARN' in line.upper(): + warnings.append((line_num, line.strip())) + + # 检查特定模式 + for pattern_name, pattern in patterns.items(): + if re.search(pattern, line, re.IGNORECASE): + pattern_matches[pattern_name].append((line_num, line.strip())) + + # 输出统计信息 + print(f"\nSummary:") + print(f" Total lines analyzed: {line_num}") + print(f" Errors: {len(errors)}") + print(f" Warnings: {len(warnings)}") + + for pattern_name, matches in pattern_matches.items(): + if matches: + print(f" {pattern_name.upper()}: {len(matches)}") + + # 显示错误示例 + if errors: + print(f"\nFirst 10 errors:") + for line_num, line in errors[:10]: + print(f" Line {line_num}: {line[:100]}") + + # 显示模式匹配示例 + for pattern_name, matches in pattern_matches.items(): + if matches: + print(f"\n{pattern_name.upper()} occurrences (first 5):") + for line_num, line in matches[:5]: + print(f" Line {line_num}: {line[:100]}") + + # 生成报告文件 + report_file = log_file + ".report.txt" + with open(report_file, 'w', encoding='utf-8') as f: + f.write(f"Log Analysis Report\n") + f.write(f"Generated: {datetime.now()}\n") + f.write(f"Source file: {log_file}\n") + f.write("=" * 60 + "\n\n") + f.write(f"Errors: {len(errors)}\n") + f.write(f"Warnings: {len(warnings)}\n\n") + + if errors: + f.write("Errors:\n") + for line_num, line in errors: + f.write(f" Line {line_num}: {line}\n") + + print(f"\nReport saved to: {report_file}") + + except FileNotFoundError: + print(f"Error: File not found: {log_file}") + return 1 + except Exception as e: + print(f"Error: {e}") + return 1 + + return 0 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Usage: python log_analyzer.py ") + sys.exit(1) + + log_file = sys.argv[1] + exit_code = analyze_logs(log_file) + sys.exit(exit_code) diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/performance_monitor.sh b/docs/Obsidian笔记体系/Resources/工具/脚本库/performance_monitor.sh new file mode 100644 index 0000000..e53491f --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/performance_monitor.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# performance_monitor.sh +# 性能监控脚本 + +PACKAGE_NAME="${1:-com.example.app}" +INTERVAL="${2:-5}" +OUTPUT_FILE="performance_${PACKAGE_NAME}_$(date +%Y%m%d_%H%M%S).csv" + +if [ -z "$PACKAGE_NAME" ]; then + echo "Usage: performance_monitor.sh [interval_seconds]" + exit 1 +fi + +echo "Monitoring performance for: $PACKAGE_NAME" +echo "Interval: ${INTERVAL} seconds" +echo "Output file: $OUTPUT_FILE" +echo "Press Ctrl+C to stop" +echo "" + +# 创建CSV文件头 +echo "Timestamp,PSS(KB),Private_Dirty(KB),Heap_Size(KB),Heap_Alloc(KB)" > "$OUTPUT_FILE" + +# 监控循环 +while true; do + timestamp=$(date '+%Y-%m-%d %H:%M:%S') + + # 获取内存信息 + meminfo=$(adb shell dumpsys meminfo "$PACKAGE_NAME" 2>/dev/null) + + if [ -n "$meminfo" ]; then + # 提取PSS + pss=$(echo "$meminfo" | grep "TOTAL" | awk '{print $2}') + + # 提取Private Dirty + private_dirty=$(echo "$meminfo" | grep "TOTAL" | awk '{print $5}') + + # 提取Heap信息 + heap_size=$(echo "$meminfo" | grep "App Summary" -A 10 | grep "java heap" | awk '{print $4}') + heap_alloc=$(echo "$meminfo" | grep "App Summary" -A 10 | grep "java heap" | awk '{print $5}') + + # 写入CSV + echo "$timestamp,$pss,$private_dirty,$heap_size,$heap_alloc" >> "$OUTPUT_FILE" + + # 显示当前状态 + printf "\r[%s] PSS: %s KB | Heap: %s KB" "$timestamp" "${pss:-N/A}" "${heap_alloc:-N/A}" + else + echo "Warning: Could not get memory info for $PACKAGE_NAME" + fi + + sleep "$INTERVAL" +done diff --git a/docs/Obsidian笔记体系/Resources/工具/脚本库/test_startup_time.sh b/docs/Obsidian笔记体系/Resources/工具/脚本库/test_startup_time.sh new file mode 100644 index 0000000..55067af --- /dev/null +++ b/docs/Obsidian笔记体系/Resources/工具/脚本库/test_startup_time.sh @@ -0,0 +1,74 @@ +#!/bin/bash +# test_startup_time.sh +# 测试应用启动时间 + +PACKAGE_NAME="${1:-com.example.app}" +MAIN_ACTIVITY="${2}" +ITERATIONS="${3:-10}" + +if [ -z "$MAIN_ACTIVITY" ]; then + # 尝试从包名推断主Activity + MAIN_ACTIVITY="${PACKAGE_NAME}/.MainActivity" +fi + +echo "Testing startup time for $PACKAGE_NAME" +echo "Main Activity: $MAIN_ACTIVITY" +echo "Iterations: $ITERATIONS" +echo "" + +total_time=0 +min_time=999999 +max_time=0 +times=() + +for i in $(seq 1 $ITERATIONS); do + # 停止应用 + adb shell am force-stop "$PACKAGE_NAME" > /dev/null 2>&1 + sleep 1 + + # 启动应用并测量时间 + result=$(adb shell am start -W -n "$MAIN_ACTIVITY" 2>/dev/null) + + if [ $? -ne 0 ]; then + echo "Iteration $i: Failed to start" + continue + fi + + # 提取TotalTime + time=$(echo "$result" | grep "TotalTime" | awk '{print $2}') + + if [ -z "$time" ]; then + echo "Iteration $i: Could not get time" + continue + fi + + echo "Iteration $i: ${time}ms" + + times+=($time) + total_time=$((total_time + time)) + + if [ $time -lt $min_time ]; then + min_time=$time + fi + + if [ $time -gt $max_time ]; then + max_time=$time + fi + + sleep 2 +done + +if [ ${#times[@]} -eq 0 ]; then + echo "No successful iterations!" + exit 1 +fi + +average=$((total_time / ${#times[@]})) +echo "" +echo "=========================================" +echo "Results:" +echo " Successful iterations: ${#times[@]}" +echo " Average: ${average}ms" +echo " Min: ${min_time}ms" +echo " Max: ${max_time}ms" +echo "=========================================" diff --git a/个人笔记体系.md b/个人笔记体系.md new file mode 100644 index 0000000..dcb93ef --- /dev/null +++ b/个人笔记体系.md @@ -0,0 +1,204 @@ +作为一位使用 Obsidian 管理笔记的高级 Android Framework 工程师,我为你设计一套兼顾 **技术深度**、**项目实践** 和 **知识演进** 的笔记目录体系。这套系统基于 **PARA 方法**(项目-领域-资源-归档)和 **MOC(内容地图)** 理念,适合长期技术积累与快速检索。 + +--- + +## 📁 **Android Framework 工程师 Obsidian 笔记体系** + +### 1. **🎯 项目 (Projects)** +_当前正在进行的项目、任务、需求开发笔记_ +``` +Projects/ +├── 项目A-系统定制化/ +│ ├── 需求与背景.md +│ ├── 技术方案设计.md +│ ├── 关键问题记录/ +│ │ ├── 2024-XX-XX-开机动画卡顿调试.md +│ │ └── 2024-XX-XX-Service重启机制优化.md +│ ├── 测试与验证记录.md +│ └── 复盘与总结.md +├── 项目B-性能优化专项/ +│ ├── 目标与指标.md +│ ├── 工具链配置(Perfetto+Systrace).md +│ └── 问题追踪列表.md +└── 项目C-XX模块重构/ + ├── 架构设计图.excalidraw + └── 迁移计划.md +``` + +--- + +### 2. **🧠 领域 (Areas)** +_需要持续精进的专业领域知识库,按模块组织_ + +``` +Areas/ +├── 01-系统启动流程/ +│ ├── Bootloader到Init.md +│ ├── Zygote进程启动.md +│ ├── SystemServer核心服务.md +│ └── Launcher启动流程.md +│ +├── 02-Activity管理/ +│ ├── Activity启动流程(跨进程).md +│ ├── Activity栈管理(Task&Stack).md +│ ├── 生命周期深度解析.md +│ └── 异常恢复机制.md +│ +├── 03-Window系统/ +│ ├── WindowManagerService架构.md +│ ├── SurfaceFlinger交互流程.md +│ ├── 窗口类型与层级.md +│ └── 触摸事件传递.md +│ +├── 04-资源与包管理/ +│ ├── PackageManagerService.md +│ ├── Resource资源加载机制.md +│ └── 动态加载与热修复原理.md +│ +├── 05-进程与线程通信/ +│ ├── Binder机制(内核到Java层).md +│ ├── Handler机制源码解析.md +│ ├── AIDL与HIDL使用与原理.md +│ └── 跨进程同步与锁优化.md +│ +├── 06-性能优化体系/ +│ ├── 启动优化方法论.md +│ ├── 内存优化(LeakCanary原理).md +│ ├── 流畅度(Choreographer+VSYNC).md +│ └── 功耗优化工具链.md +│ +├── 07-系统安全/ +│ ├── SELinux策略编写.md +│ ├── 权限管理框架.md +│ ├── 密钥存储与加密.md +│ └── 漏洞案例库.md +│ +├── 08-定制化开发/ +│ ├── 系统属性定制.md +│ ├── 系统服务添加流程.md +│ ├── 开机动画与OTA.md +│ └── 厂商定制接口规范.md +│ +└── 09-调试与工具链/ + ├── ADB高级命令.md + ├── GDB/LLDB调试Native.md + ├── Systrace/Perfetto全解读.md + └── 自定义调试工具开发.md +``` + +--- + +### 3. **📚 资源 (Resources)** +_外部收集的参考资料、文章、论文、工具_ + +``` +Resources/ +├── 论文/ +│ ├── Android系统优化论文/ +│ └── 移动操作系统前沿/ +├── 技术文章/ +│ ├── 官方文档笔记/ +│ ├── 优质博客归档(Gityuan等)/ +│ └── 内核相关文章/ +├── 工具/ +│ ├── 脚本库/ +│ └── 效率工具推荐/ +└── 会议与分享/ + ├── Android开发者峰会笔记/ + └── 内部技术分享记录/ +``` + +--- + +### 4. **🗃️ 归档 (Archive)** +_已完成或暂停的项目、过时但仍有参考价值的笔记_ + +``` +Archive/ +├── 项目-旧版ROM适配/ +├── 领域-已废弃API研究/ +└── 资源-历史会议记录/ +``` + +--- + +### 5. **🧭 导航与索引 (Maps of Content)** +_核心枢纽,连接碎片知识,形成知识网络_ + +``` +MOCs/ +├── Android Framework知识体系图.md +│ - 用双向链接将各领域模块关联,形成全景图 +├── 高频问题索引.md +│ - 例如:“开机ANR” → 链接到启动流程、Handler、性能工具等笔记 +├── 源码阅读地图.md +│ - 记录AOSP源码阅读路径(如ActivityThread → Instrumentation → AMS) +└── 技能提升路线图.md + - 阶段性学习目标与完成情况 +``` + +--- + +### 6. **📓 工作日志 (Daily Notes)** +_每日工作记录、临时想法、会议记录_ + +``` +Daily/ +├── 2024-06-01.md +├── 2024-06-02.md +└── templates/ + └── 每日模板.md +``` +*模板建议包含:今日重点、问题记录、明日计划、临时灵感* + +--- + +### 7. **🛠️ 模板库 (Templates)** +_标准化笔记模板,提升记录效率_ + +``` +Templates/ +├── 问题排查模板.md +│ - 现象描述、可能原因、排查步骤、根本原因、解决方案 +├── 技术方案设计模板.md +├── 会议记录模板.md +└── 源码解析模板.md +``` + +--- + +### 8. **⚙️ 配置与脚本 (Config)** +_Obsidian 插件配置、自定义脚本_ + +``` +Config/ +├── 插件列表与配置.md +├── 自定义脚本/ +│ ├── 自动生成日报.js +│ └── 源码链接生成器.py +└── 主题与样式.css +``` + +--- + +## 🔧 **使用建议** + +1. **标签系统**: + - 使用 `#bug`、`#optimization`、`#hard` 标记问题类型 + - 使用 `#prd`、`#review`、`#done` 标记笔记状态 + +2. **双向链接**: + - 在笔记中大量使用 `[[ ]]` 链接相关概念 + - 使用 `![[ ]]` 嵌入关键图表或代码片段 + +3. **图谱利用**: + - 定期查看知识图谱,发现隐藏联系 + - 为核心概念创建“中心笔记”(Hub Notes) + +4. **定期复盘**: + - 每周整理 `Daily Notes` 到对应领域或项目 + - 每月更新 `MOCs`,重构知识结构 + +--- + +这套体系能够帮助你在 **深度开发**、**问题排查**、**技术演进** 之间自由切换,既满足日常工作记录,又构建持续增长的技术知识库。你可以根据实际工作流微调,关键是保持 **持续记录** 和 **有效连接**。 \ No newline at end of file