Mr.HeXiang Blog

记录学习,学习记录


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 公益404

常用命令

贺祥 | 发表于 2023-09-04 | 分类于 Android

####

常用命令

  1. 查看当前view 的数量,和数据库地址
1
adb shell dumpsys meminfo com.duowan.gamevoice
  1. dump hprof 必须 是/data/local/tmp/目录
1
adb shell am dumpheap com.duowan.gamevoice /data/local/tmp/test001.hprof

拉取到电脑当前目录下

1
adb pull /data/local/tmp/test001.hprof

3.Mat 查看导出来的hprof 需要转换

转换之后Mat 就可以打开了

1
hprof-conv test001.hprof test001_new.hprof

4.查看当前activity数量

查看当前运行activity 栈

1
adb shell dumpsys activity activities

查看当前运行的activity

1
adb shell dumpsys activity activities | sed -En -e '/Stack #/p' -e '/Running activities/,/Run #0/p'
1
2
3
4
5
6
7
8
9
10
11
12
13
adb shell dumpsys activity ----------查看ActvityManagerService 所有信息

adb shell dumpsys activity activities ----------查看Activity组件信息

adb shell dumpsys activity services ----------查看Service组件信息

adb shell dumpsys activity providers ----------产看ContentProvider组件信息

adb shell dumpsys activity broadcasts --------查看BraodcastReceiver信息

adb shell dumpsys activity intents--------------查看Intent信息

adb shell dumpsys activity processes---------查看进程信息

adb 查看当前系统的版本号

1
adb shell getprop ro.build.version.release

查看当前系统里面WakeLock的使用规则

1
adb shell dumpsys powe

获取数据库

1
2
3
4
5
6
7
8
9
10
11
12
13
adb shell run-as com.duowan.gamevoice

cd databases

#进入数据库目录

cp 123.db /sdcard/123.db

#把数据库拷贝到sdcard

adb pull /sdcard/123.db

#把数据库从sdcard从获取到电脑

sqlite3 123.db 打开数据库查询

退出sqlite3

…> 的时候输入分号退出;

1
2
3
4
5
...> ;

Error: near "sql": syntax error

sqlite>

sqlite> 输入.exit或者.quit

1
2
3
sqlite> .quit

hexiang@hexiangdeMacBook-Pro gamevoice-android_1612804294492 %

如果想列出该数据库中的所有表,可:

1
.table

如果想查看这些表的结构:

1
select * from sqlite_master where type="table";
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#写个脚本快速dump 出内存堆
rm -rf heap

adb shell rm /data/local/tmp/xx.hprof

PRO=$1

pid=`adb shell ps |grep $PRO |grep -v ":" |awk -F " " '{print $2}'`

echo $pid

adb shell am dumpheap $pid /data/local/tmp/xx.hprof

sleep 3

adb pull /data/local/tmp/xx.hprof

sleep 0.5

hprof-conv -z xx.hprof out.hprof

sleep 0.5

mkdir heap

mv out.hprof heap

rm xx.hprof
1
2
3
chmod +x dump_process_java_heap.sh

./dump_process_java_heap.sh duowan

Debug.startMethodTracing(“/sdcard/gameVoiceMethodTrace_app”);

getPackageInfo 是耗时任务

环境变量设置

1
vim ~/.zshrc

在~/.zshrc 文件中输入环境变量 ,或者加载环境变量,/etc/profile里面是一些export环境变量

export PATH=$PATH::::——:

1
source /etc/profile

查看某个库的依赖

1
./gradlew :gamevoice_client:dependencyInsight --configuration debugRuntimeClasspath --dependency stdlib

将当前目录及其子目录下所有文件后缀为 .c 的文件列出来

1
# find . -name "*.c"

将目前目录其其下子目录中所有一般文件列出

1
# find . -type f

将当前目录及其子目录下所有最近 20 天内更新过的文件列出:

1
# find . -ctime -20

systrace 生成html

1
systrace.py -a com.duowan.gamevoice view gfx sched am dalvik -t 15
1
2
3
systrace.py -a com.duowan.gamevoice sched freq idle am wm gfx view binder_driver hal dalvik camera input res -t 20

systrace.py -a com.duowan.gamevoice sched freq idle am wm gfx view binder_driver hal dalvik camera input res

只要带上sched 就可以看到自定义的beginSection

设置系统配置,开启systrace

1
2
3
//adb shell setprop log.tag.MyAppTag VERBOSE

adb shell setprop log.tag.YTraceCompat D

获取系统配置

1
adb shell getprop
1
`These categories are unavailable: ***说明当前设备不支持`这个类别或选项

查看当前设备所支持的类别或选项:

1
2
3
4
5
systrace.py --list-categoriedsew s34d sx2sedsxzc

-h | --help 显示帮助消息。

-l | --list-categories 列出您的已连接设备可用的跟踪类别。

查看当前应用的自定义事件如

TraceCompat.beginSection(“name”)

使用 app 生成的html就有自定义事件

1
systrace.py -a com.duowan.gamevoice app

或者

1
systrace.py -a com.duowan.gamevoice android
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
绿色:正在运行

线程正在完成与某个进程相关的工作或正在响应中断。

蓝色:可运行

线程可以运行但目前未进行调度。

白色:休眠

线程没有可执行的任务,可能是因为线程在遇到斥锁定时被阻止。

橙色:不可中断的休眠

线程在遇到 I/O 操作时被阻止或正在等待磁盘操作完成。

紫色:可中断的休眠

线程在遇到另一项内核操作(通常是内存管理)时被阻止。

dump 当前activity的信息

1
adb shell dumpsys activity com.duowan.gamevoice >> black2.txt

打开当前文件夹

1
open .

多个设备连接,adb shell指定设备执行命令

1
adb -s 8f7e64ba shell dumpsys meminfo

查看java 安卓目录

1
/usr/libexec/java_home -V

systrace.py -a com.duowan.gamevoice sched freq idle am wm gfx view binder_driver hal \

dalvik camera input res

使用

vim /etc/profile

1
2
3
export ANDROID_NDK_HOME=/Users/hexiang/ndk/android-ndk-r16b

export PATH=${PATH}:${ANDROID_NDK_HOME}

导出数据库db

1
adb exec-out run-as com.duowan.gamevoice tar c databases/ > databases.tar

cat *.txt |egrep -ia “send_failed:”

/GVJump/Jump/user/receive_gift_list?uid=123

exitChannelBroadcast

uid=3304541490

升级android sutdio ide 之后native debug 不了解决办法

1.新建个native 测试demo gradle 会提示,首选的ndk版本

如21.4.7075529

2.gradle 升级

1
classpath "com.android.tools.build:gradle:4.2.1"

查看activity 所有日志命令

1
adb -d logcat -b events -v time -d

查找文件

1
find . -type f -name "*.jar" | xargs grep "TODO"

分析性能好坏

可以使用 adb shell dumpsys gfxinfo ,使用方法如下

首先确定要测试的包名,到 App 界面准备好操作

执行2-3次 adb shell dumpsys gfxinfo com.miui.home framestats reset ,这一步的目的是清除历数据

开始操作(比如使用命令行左右滑动,或者自己用手指滑动)

操作结束后,执行 adb shell dumpsys gfxinfo com.miui.home framestats 这时候会有一堆数据输出,我们只需要关注其中的一部分数据即可

重点关注

Janky frames :超过 Vsync 周期的 Frame,不一定出现卡顿

95th percentile :95% 的值

HISTOGRAM : 原始数值

PROFILEDATA :每一帧的详细原始数据

进出启动查看

1
adb logcat -b events | egrep "am_proc_died|am_proc_start"

activity启动查看

1
adb logcat -b events | egrep -ia "activity

sudo xcode-select –switch /Users/hexiang/Downloads/Xcode.app/Contents/Developer

查看flutter 安装目录

1
flutter doctor -v

gfxinfo 还可以拿到渲染相关的内存和 View hierarchy 信息。在 Android 6.0 之后,gxfinfo 命令新增了 framestats 参数,可以拿到最近 120 帧每个绘制阶段的耗时信息。

1
adb shell dumpsys gfxinfo com.duowan.gamevoice framestats

Surface 都会有三个 Graphic Buffer,那如何查看 Graphic Buffer 占用的内存,系统是怎么样管理这部分的内存的呢

1
adb shell dumpsys SurfaceFlinger

dumpsys gfxinfo的信息详解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Graphics info for pid 31148 [com.android.settings]: 表明当前dump的为设置界面的帧信息,pid为31148

Total frames rendered: 105 本次dump搜集了105帧的信息

Janky frames: 2 (1.90%) 105帧中有2帧的耗时超过了16ms,卡顿概率为1.9%

Number Missed Vsync: 0 垂直同步失败的帧

Number High input latency: 0 处理input时间超时的帧数

Number Slow UI thread: 2 因UI线程上的工作导致超时的帧数

Number Slow bitmap uploads: 0 因bitmap的加载耗时的帧数

Number Slow issue draw commands: 1 因绘制导致耗时的帧数

HISTOGRAM: 5ms=78 6ms=16 7ms=4 ... 直方图数据,表面耗时为0-5ms的帧数为78,耗时为5-6ms的帧数为16,同理类推

AGi 安装失败

Android GPU Inspector (AGI)

1
2
3
I20220106-103713027[server.ChildProcess-gapis][server.ChildProcess.runProcess] Killing gapis

W20220106-103713028[server.ChildProcess-gapis][server.ChildProcess.onExit] The gapis process exited with a non-zero exit value: -1

host 找不到映射本地ip

1
2
3
4
5
6
7
8
9
hexiang@hexiangdeMacBook-Pro ~ % /Applications/AGI.app/Contents/MacOS/gapis ; exit;

02:41:19.306 I: <gapis> Adding new device

02:41:19.306 I: <gapis> New scheduler for device: 8a60cfa8aad527f1ebf79cf9a1767881cfd5fa70

02:41:19.306 I: <gapis> New trace scheduler for device: 8a60cfa8aad527f1ebf79cf9a1767881cfd5fa70 hexiangdeMacBook-Pro.local

02:41:19.328 F: <gapis> Could not start grpc server at localhost:0: listen tcp: lookup localhost: no such host

下载个switchhost 软件配置下host

https://github.com/oldj/SwitchHosts

1
127.0.0.1 localhost

app_package=

abi=arm64v8a # Possible values: arm64v8a, armeabi-v7a, x86

adb shell settings put global enable_gpu_debug_layers 1

adb shell settings put global gpu_debug_app com.example.ponycui_home.svgaplayer

adb shell settings put global gpu_debug_layer_app com.google.android.gapid.armeabi-v7a

adb shell settings put global gpu_debug_layers VK_LAYER_KHRONOS_validation

systrace.py -a com.duowan.gamevoice sched am wm gfx view dalvik input res -t 20

mac安装了多个java版本

1
2
3
4
5
6
7
8
9
10
11
#查看安装了几个java

/usr/libexec/java_home -V

#查看当前java版本

java -version

#设置当前terminal 使用哪个java版本,设置路径就可以了

export JAVA_HOME=/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home

jdk环境配置

1
2
3
4
5
export JAVA_HOME=/Applications/Android\ Studio.app/Contents/jbr/Contents/Home

export PATH=$JAVA_HOME/bin:$PATH

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

崩溃异常辅助日志搜集

/system/bin/logcat 手机自己的日志工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#查看崩溃日志缓冲区(默认)

/system/bin/logcat -b crash

#查看系统系统事件缓冲区消息

/system/bin/logcat -b events

#查看主要日志缓冲区(默认),不包含系统和崩溃日志消息。

/system/bin/logcat -b main

#查看系统日志缓冲区(默认)

/system/bin/logcat -b system

android debug 系统进程

debug系统进程需要root权限

下载模拟器需要下载不带google play 和google api的

下载 android xx.x 后面直接显示版本的,这个是自带root的

4befe29077ca05a21ea769d1482dc48e.png

62d9647d67561455a0a98383addd268f.png

查看所有进程内存情况

1
adb shell procrank

性能优化-卡顿

贺祥 | 发表于 2023-09-04 | 分类于 Android
性能优化-卡顿

卡顿
线上监控方法:
方法1:Coreographer帧率检测,postFrameCallback ,保存两次 doFrame 时间进行相减然后除以刷新频率,这样算出来的结果就是两次 doFrame 的掉帧数

方法2:Looper设置print ,匹配消息分发前后字符串,计算之间的耗时

方法3:开启个线程循环通过主线程Handle,post一个延迟x秒的消息去修改一个值,睡眠x秒后在去看下这个值是否修改了

线下监控方法
1、利用Systetrace工具

1
systrace.py -a com.duowan.gamevoice sched freq idle am wm gfx view binder_driver hal dalvik camera input res

只要带上sched 就可以看到自定义的beginSection

2、profile traceView 打印出详细调用堆栈
profile 手动记录时间段
指定监控方法,通过代码自定义开始和结束,有的文件分析不了可能是后面参数设置太小了,文件写的不全

1
Debug.startMethodTracing("/sdcard/gameVoiceMethodTrace_app",1024*1024*20);

3、系统自带工具 StrictMode
避免主线成io耗时操作
使用StrictMode 检测主线程是否有io,网络等耗时操作会打印到logcat中

// 启用 StrictMode
    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
        .detectAll() // 检测所有问题
        .penaltyLog() // 输出问题信息到日志
        .build();

    StrictMode.setThreadPolicy(policy);

4、第三方工具:BlockCananry

ANR

  1. 什么是ANR?
    当应用程序在一段时间内未能响应用户输入或系统事件时,Android系统会主动生成ANR错误
    ANR一般有以下几种类型,具体数值

    • KeyDispatchTimeout:按键事件在5s的时间内没有处理完成。

    • BroadcastTimeout:广播接收器在前台10s,后台60s的时间内没有响应完成。

    • ServiceTimeout:服务在前台20s,后台200s的时间内没有处理完成。

      主线程阻塞,广播接收器处理耗时,服务未响应,服务执行耗时任务,主线程死锁等都可能会导致ANR

      但并不一定主线程耗时任务就会出现anr如下面这种情况,如果后续没有事件需要处理是不会产生anr的
      8a0823ee154241d9d1a8c25671cd2058

  2. ANR如何监控
    方法一:6.0 以下手机监听 用FileObserver 监听/data/anr/trace.txt 文件,变化了之后调用AMS 获取进程状态,getProcessesInErrorState

    方法二:6.0 以上获取 通过jni 调用 sigaction 注册监听 SIGQUIT信号,然后在去AMS查询状态。signal 3信号就是ANR

    方法三:直接定期轮训查AMS的状态

    方法四:AnrWatchDog,原理:开启个线程循环通过主线程Handle,post一个延迟x秒的消息去修改一个值,睡眠x秒后在去看下这个值是否修改了,没有判断为ANR,还可以查询小AMS状态二次校验下。非侵入式,不需要hook

  3. ANR trace文件获取
    线下收集trace文件

    1
    2
    #适合6.0 以下
    adb pull /data/anr/trace.txt

线上收集trace,
通过sigaction 设置个signalHandler

5d1cb110e2b99a3a802b6253b08b2331

25b204164d9e7690496f1803597bbab2

Xhook hook write 函数拿到trace文件,这个文件包含很全面的anr信息
9c38971886e1c4b71365960bc3769841

1
2
#适合6.0以上,没有权限获取了
adb bugreport
崩溃异常辅助日志搜集
/system/bin/logcat 手机自己的日志工具,也可以用adb locat
1
2
3
4
5
6
7
8
9
10
11
#查看崩溃日志缓冲区(默认)
/system/bin/logcat -b crash

#查看系统系统事件缓冲区消息
/system/bin/logcat -b events

#查看主要日志缓冲区(默认),不包含系统和崩溃日志消息。
/system/bin/logcat -b main

#查看系统日志缓冲区(默认)
/system/bin/logcat -b system
通过popen获取得到输入命令文件,然后fgets读出结果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
char* types[] = {"crash", "system", "events", "main"};
int lines[] = {10000, 5000, 5000, 10000};
CrashLogWriter::GUIDInstance()->WriteLogFormat(
"logcat %s", SEGMENT_BEGIN);
for (int i = 0; i < 4; i++) {
char cmd[128];
FILE *fp;
char buf[1025];
snprintf(cmd, sizeof(cmd), "/system/bin/logcat -b %s -d -v threadtime -t %u -d *:D",
types[i], lines[i]);
if(NULL != (fp = popen(cmd, "r")))
{
buf[sizeof(buf) - 1] = '\0';
while(NULL != fgets(buf, sizeof(buf) - 1, fp))
CrashLogWriter::GUIDInstance()->WriteFile(buf);
pclose(fp);
}
CrashLogWriter::GUIDInstance()->WriteLogFormat("tail of %s %s", types[i], SEGMENT_END);
}

功耗优化:
SurfaceView 替换 TextureView
CPU 数据上看,SurfaceView 要比 TextureView 优化 8%-13%
功耗数据上看,SurfaceView 要比 TextureView 平均功耗低 20mA 左右。

硬件绘制,代替软件绘制
视频硬编解替换软编解
减少过度绘制
减少刷新区域
减少刷新频率
CPU负载优化
长链接心跳
GSP
耗

性能优化-内存

贺祥 | 发表于 2023-09-04 | 分类于 Android
性能优化-内存

Shallow Size
对象自身占用的内存大小,不包括它引用的对象

Retained Size
当前对象大小+当前对象可直接或间接引用到的对象的大小总和

Bitmap内存在native中,不影响java虚拟机内存上限,android 8.0之后才在native中的,测试系统api 34模拟器中,循环调用BitmapFactory.decodeResource创建bitmap只是native内存增长

code,stack,java变化很小,只有native和other 的内存一直在增长
b58dc04118154515f020948120ebaa02

每次创建bitmap对cpu都有一定的消耗
7da8ca02a98712a09e9a72627660bae4

java对象内存很小
87c4f03fc12800b0dfce61688978b46d

native内存已经1.3G多了,java 虚拟机内存的内存也没有过多变化
80168fddcd4bf7ef6dbbd1d282769a12

被强制杀掉进程了
5768e37e872a9c1662668979df1bf56f

陆续杀了一些其他进程,接着是demo进程
系统终止进程 “com.example.jnidemo” 来缓解内存和交换空间的压力,java虚拟机没有达到上限,但native 尝试分配太多内存也会被杀掉,可以主动释放些内存,实际中除了泄露应该用不这么多内存的
2f758fb912cc4ff71a246c0e36604273

换个真手机,1200块的普通oppo手机,总内存达到8.8G,natvie 3.7G,others 5G,才被杀掉
928e9f5dccf4a79c671ab1596f7af2ec

通过bitmap创建申请了几乎8g的native 内存,但java 虚拟机内存一点变化都没有
9af3917956e332ce6e487da3f842e669

RGB_565格式设置不一定生效,系统会查看当前图片是否有透明通道,没有透明通道的是你才会生效,如下面代码,只有把图片去掉图透明通道,才是每像素4字节,否则都是8字节每像素

1
2
3
val optionsNew = BitmapFactory.Options()                optionsNew.inPreferredConfig = android.graphics.Bitmap.Config.RGB_565

BitmapFactory.decodeResource(resources, R.mipmap.testtemplatenoalpha, optionsNew)

Bitmap.createBitmap 也是放native中

Bitmap对象,java层的Bitmap对象很小,其中通过一个mNativePtr native bitmap 的指针,关联native分配的内存

1
Bitmap.createBitmap(1024,1024,Bitmap.Config.ARGB_8888)

内存分析工具及方式:
Profiler
可以直观的看到实时的各类型内存,还可以捕获堆转储,只适合线下

内存计数中的类别:

Java:从 Java 或 Kotlin 代码分配的对象的内存。
Native:从 C 或 C++ 代码分配的对象的内存。

即使您的应用中不使用 C++,您也可能会看到此处使用了一些原生内存,因为即使您编写的代码采用 Java 或 Kotlin 语言,Android 框架仍使用原生内存代表您处理各种任务,如处理图像资源和其他图形。

Graphics:图形缓冲区队列为向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。(请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)

Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存。这通常与您的应用运行多少线程有关。

Code:您的应用用于处理代码和资源(如 dex 字节码、经过优化或编译的 dex 代码、.so 库和字体)的内存。

Others:您的应用使用的系统不确定如何分类的内存。

Allocated:您的应用分配的 Java/Kotlin 对象数。此数字没有计入 C 或 C++ 中分配的对象。

dump简易信息

1
adb shell dumpsys meminfo com.example.jnidemo

看到大致内存信息,像code,native heap dex so等
45fdf95595e0af352cd50576f72c2954

内存统计,Activity数量和view的数量
83651dc13a6e2cf59f7a5eb27cd71830

看更详细的信息,这个需要debug包

1
adb shell run-as com.example.jnidemo cat /proc/18047/maps

2b57e7029fc339703a800166a51b9f01

可以用个python脚本把上面的内存地址计算成大小,做个排序

35154a15ef10436033e9a0d092c14f2c

用命令dump内存堆
dump 内存堆到指定目录

1
adb shell am dumpheap $pid /data/local/tmp/xx.hprof

还需要调用 转成能够分析的hprof

1
hprof-conv -z xx.hprof out.hprof

可以写成一个脚本把上面两步骤写在一起,dump出来的会在当前目录的heap目录里面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rm -rf heap
adb shell rm /data/local/tmp/xx.hprof
PRO=$1
pid=`adb shell ps |grep $PRO |grep -v ":" |awk -F " " '{print $2}'`
echo $pid
adb shell am dumpheap $pid /data/local/tmp/xx.hprof
sleep 3
adb pull /data/local/tmp/xx.hprof
sleep 0.5
hprof-conv -z xx.hprof out.hprof
sleep 0.5
mkdir heap
mv out.hprof heap
rm xx.hprof

第三方性能分析工具:
PerfDog性能狗 开始收费了
火山引擎性能分析工作台目前已找不到下载入口了,估计是开始针对性能收费了
自行开发个,思路利用adb + app_process + socket 提权获取信息开发个桌面性能分析工具

Mat工具

Leak Suspects:直击引用链条上占用内存较多的可疑对象,可解决一些基础问题,但复杂的问题往往帮助有限。

Top Consumers:展现哪些类、哪些 class loader、哪些 package 占用最高比例的内存。

Path To GC Roots:提供任一对象到GC Root的链路详情,帮助了解不能被 GC 回收的原因。在排除弱引用

Dump 前主动手动执行一次 FULL GC,profiler 工具可以触发 ,去除无效对象进一步减少 dump 堆转储及建立索引的时间

线下内存检测
LeakCanary
LeakCanary1.0版本的HAHA解析引擎,解析速度很慢,解析过程很容易oom
KOOM基于Shark引擎进行解析
LeakCanary2.0版本使用Shark新版解析引擎
线下大图检测
AMS插桩修改字节码,修改imageview的父类获得view的高宽和bitmap的高宽

线上检测
达到阀值,触阀dump,子线程dump或者,另起进程dump内存堆,然后通过mat软件分析分析
裁剪Hprof文件,以降低后台存储Hprof的开销
快手的Koom
大量OOM分析:时候通过shark或者haha库分析捞上来dump堆,把数据入库,统计聚合分析

主动释放内存
定期主动释放部分内存
特殊场景下,释放内存,如长时间在后台
收到onTrimMemory信号主动释放内存
达到阀值释放部内存
android虚拟机内存使用计算

1
Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();

StrictMode
检测出一些不合理的代码块。
StrictMode分为线程策略(ThreadPolicy)和虚拟机策略(VmPolicy)

检测对IO、网络、数据库等相关操,主线程耗时操作,通过其相应崩溃日志定位问题

Activity显示原理

贺祥 | 发表于 2021-12-11 | 分类于 Android

####

Activity的显示原理(Window/DectorView/ViewRoot)
  1. activity.attach 生成个phonewindow

  2. activity.onCrate 生命周期

  3. setContentView 加载布局,会调用phonewindow创建dectorView(FrameLayout),加载布局到dectorView,生成个viewtree ,现在还没有显示

  4. handleResumeActivity onresume 之后,创建个ViewRootimpl把dectorView 添加到ViewRootImpl,交给ViewRootImpl管理,一个surface 一个ViewRootImpl,ViewRootImpl可以和WMS通信,相互调用

  5. viewRootImpl 触发requestLayout,

Activity的ui刷新机制(Vsync/Choreographer)
  1. requestLayout

  2. scheduleTraversals,会发一个屏障消息,阻塞普通消息,给ui绘制开个绿色通道

  3. 下次Vsync信号来的时候触发doTraversals调用

  4. performTraversals,真正执行绘制,第一次会像WMS申请一个surface,有了surface之后接下来绘制就会frameBuffer,之后提交到SurfaceFlinger 合成图像,写到屏幕缓冲区就会显示出来

  5. performMesaure

  6. performLayout

  7. perfromDraw

UI绘制原理(Measure/Layout/Draw)

测量,布局,绘制

Surface原理(Surface/SurfaceFlinger)

ViewRootImpl 第一次绘制的时候会像WMS申请窗口,WMS统一管理所有窗口大小层级

Activity启动流程

贺祥 | 发表于 2021-12-09 | 分类于 Android

####

Activity启动流程
  1. context.startActivity调用AMS系统服务,发起binder调用

  2. 是否需要创建进程,执行进程启动流程,同时挂起Activity或者service等相关组件,等待进程启动完成

    #进程启动流程
    2.1 AMS像Zygote通过socket发送命令启动进程
    2.2 Zygote收到命令会调用runeOnce方法,fork进程
    2.3 zygote fork用进程后,会执行ActivityThread的Main函,这个ActivityThread类入口来自AMS发送的Socket参数
    2.4 进程启动后会像AMS报告,attachApplication binder调用
    
  3. 进程启动好后AMS 通过binder调用应用的bindApplication,初始化应用

  4. 创建Acitivty 对象,准备好aplication,创建contextImpl,attach 上下文

  5. 生命周期回调 OnCreate

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    /**  Core implementation of activity launch. */
    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ContextImpl appContext = createBaseContextForActivity(r);

    try {
    java.lang.ClassLoader cl = appContext.getClassLoader();
    activity = mInstrumentation.newActivity(
    cl, component.getClassName(), r.intent);
    } catch (Exception e) {
    if (!mInstrumentation.onException(activity, e)) {
    throw new RuntimeException(
    "Unable to instantiate activity " + component
    + ": " + e.toString(), e);
    }
    }

    try {
    Application app = r.packageInfo.makeApplicationInner(false, mInstrumentation);
    if (activity != null) {
    activity.attach(appContext, this, getInstrumentation(), r.token,
    r.ident, app, r.intent, r.activityInfo, title, r.parent,
    r.embeddedID, r.lastNonConfigurationInstances, config,
    r.referrer, r.voiceInteractor, window, r.activityConfigCallback,
    r.assistToken, r.shareableActivityToken);
    if (theme != 0) {
    activity.setTheme(theme);
    }
    if (r.isPersistable()) {
    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    } else {
    mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    }

    } catch (SuperNotCalledException e) {
    throw e;

    } catch (Exception e) {
    }

    return activity;
    }
  6. 接着activity 显示原理

Android启动binder机制

贺祥 | 发表于 2021-06-10 | 分类于 Android

####

binder是什么

binder是跨进程的ipc通信,跟管道,共享内存,信号等不同,它是一个android系统创建的全新的IPC通信,基于binder驱动,

可以跨进程调用函数,传输大图片

binder的优点
  1. 性能

    linux常用的进程通信比如socket,管道等是需要内核作为中转的,需要两次数据copy,一次从应用层copy到内核,一次从内存copy到应用层。然而binder是给一块物理内存同时映射到内核和目标进程的用户空间,将数据从应用层copy到内核空间时,相当于将数据copy到了另一个进程的用户空间了,只用copy一次。

  2. 方便易用

    逻辑简单直接,不易出现问题。共享内存虽然性能很好,但远不如binder好用

  3. 安全

    普通的linux跨进程访问是很不安全的,比如socket,它的IP地址端口等都是开放的,别人只要知道了他的IP地址就能链接他。或者说命名管道也是,知道了管道的名字就能读写数据了,这很容易被人恶意利用的。主要是我们拿不到调用方可靠身份信息,身份信息总不能让调用方自己填写,这明显是不可靠的,可靠的方式这个身份信息只能有IPC机制本身在内核态中添加,关于这点binder是做到了。

bindder架构

系统服务的binder通信架构,只有系统服务才能注册到serviceManager, 应用端的服务是不能注册到serviceManager的,通过不了权限验证。

Client:应用进程

Server:系统服务,可能运行在SystemServer进程或单独的进程,Server先与Client/应用启动,Server先与ServiceManager交互的,Server启动时将自己的binder注册到ServiceManager

ServiceManager: 单独的系统进程,Servicemanager启用binder机制后进入loop循环,等待Client和Server的请求

这三种进程启动时都会先启动binder机制,这是binder通信的前提

bind机制启动
  • 打开binder驱动

  • 映射虚拟内存,分配内存缓冲区

  • 注册binder线程

  • 进入binder loop

Android启动binder机制

贺祥 | 发表于 2021-02-06 | 分类于 Android

####

启动binder时机

启动时间必须是在进程fork之后,初始化中,调用AMS之前

1
2
3
virtual void onZygoteInit() {
sp<ProcessState> proc = ProcessState::self();
proc->startThreadPool(); //启动新binder线程 }
启动binder机制
  1. 打开binder驱动

  2. 映射虚拟内存,分配内存缓冲区

  3. 注册binder线程

  4. 进入binder loop

android应用进程启动

贺祥 | 发表于 2020-12-05 | 分类于 Android

####

Android应用进程启动
  1. 在启动组件Activity或者service,如果所在进程没有启动,就会启动进程

  2. AMS像Zygote通过socket发送命令启动进程

  3. Zygote收到命令会调用runeOnce方法,fork进程

  4. zygote fork用进程后,会执行ActivityThread的Main函,这个ActivityThread类入口来自AMS发送的Socket参数

  5. 进程启动后会像AMS报告,启动才算结束

zygote会返回pid到AMS,注册IApplicationThread到AMS即app.thread。判断app是否启动,是通过判断app!=null &&app.thread!=null

Zygote的理解

贺祥 | 发表于 2020-10-09 | 分类于 Android

####

Zygote的作用
  1. 启动SystemServer

  2. 孵化应用进程

zygot启动过程
  1. init进程根据init.rc配置fork出zygote进程
app_main.cpp的main函数中的AppRuntime的start 方法来启动Zygote进程的
  1. 启动Android虚拟机,注册jni函数

  2. 预加载系统资源

  3. 启动Systemserver

  4. 注册socket,开启无限循环,通过监听socket,等待AMS命令fork进程

Zygote的IPC为什么不采用binder

zygote fork 需要单线程,需要停掉其他线程,启动之后再恢复,如果是binder,子进程其他线程状态无法恢复

ServcieManger启动和工作原理

贺祥 | 发表于 2020-05-09 | 分类于 Android

####

ServcieManger启动和工作原理
  • 调用函数 binder_open 打开设备文件 /dev/binder 以及将它映射到本进程的地址空间.
  • 调用函数 binder_become_context_manager 将自己注册为所有服务的大管家.
  • 调用函数 binder_loop 来循环等待和处理 Client 进程的通信请求.
12…13
贺祥

贺祥

记学学记

123 日志
10 分类
65 标签
© 2023 贺祥
由 Hexo 强力驱动「Hosted by Coding Pages」
|
主题 — NexT.Pisces v5.1.3