安卓线程相关

linux线程posix实现方案

每个线程都有一个线程ID

c 复制代码
/* 用于表示线程ID数据结构 */
pthread_t // 每个线程都有一个线程ID

/* 线程创建 */
pthread_create()

/*
__newthread:函数成功返回将ID存储在此变量中。
__attr:定制线程属性。
__start_routine:函数指针。
__arg:传递给函数的参数。
*/
int pthread_create (pthread_t *__restrict__newthread,
               const pthread_attr_t *__restrict__attr,
               void *(*__start_routine) (void *),
               void *__restrict__arg);

新知识

man命令

thread_posix.c中使用了exit(0)abort(),一开始没有引入对应的头文件,就报错了,说这两个地方有问题。

可以在linux服务器中使用man exitman abort来查看是哪个头文件,然后再引入即可。

man是一个用于查看系统手册页(manual pages)的命令,其名称来源于"manual"的缩写,作用是提供关于命令、函数、系统调用等的技术文档。

man的含义与作用

  • 名称来源man是"manual"的缩写,意为手册或指南。
  • 作用man命令用于查看Linux系统中各种命令、函数、系统调用等的手册页。这些手册页提供了详细的说明、用法示例、参数解释等信息,是开发者和管理员的重要参考资料。
  • 使用方法 :在终端中输入man命令,后跟要查询的命令、函数或系统调用的名称。例如,man ls用于查看ls命令的手册页,man abort用于查看abort函数的手册页。

ls -l

ruby 复制代码
ZM10:/system/bin $ ls -l bootanimation
-rwxr-xr-x 1 root shell 23504 2026-03-21 16:07 bootanimationls

分析 ls -l命令的输出格式:

我来帮你详细分析 ls -l命令的输出格式,一次教会你!

1. 整体输出结构

diff 复制代码
-rwxr-xr-x 1 root shell 23504 2026-03-21 16:07 bootanimation

这是一个完整的文件信息行,共7个字段。

2. 各字段详解(从左到右)

字段1:文件类型和权限 (-rwxr-xr-x)

第1个字符:文件类型

-= 普通文件

d= 目录

l= 符号链接

b= 块设备文件

c= 字符设备文件

第2-10个字符:权限(每3位一组)

第2-4位:所有者权限(u = user)

第5-7位:所属组权限(g = group)

第8-10位:其他人权限(o = others)

权限字符含义:

r= 读权限

w= 写权限

x= 执行权限

-= 无对应权限

字段2:硬链接数 (1)

表示该文件有多少个硬链接

目录至少为2(...

字段3:所有者 (root)

文件的所有者用户

字段4:所属组 (shell)

文件所属的用户组

3. 实战分析示例

diff 复制代码
-rwxr-xr-x 1 root shell 23504 2026-03-21 16:07 bootanimation

分析结果:

这是一个普通文件

权限:所有者(root)可读、写、执行;组成员可读、执行;其他人可读、执行

1个 硬链接

所有者是 root 用户

所属组是 shell

文件大小为 23504字节(约23KB)

最后修改于 2026年3月21日 16:07

文件名为 bootanimation

安卓封装的Thread类

Android native的Thread类是Android提供的一个基础类,源码路径: system\core\libutils\include\utils\Thread.h system\core\libutils\Threads.cpp

安卓封装的Thread类使用了linux线程posix的实现方案。


Thread.h中可以看到,Thread继承了 RefBase 类,而本身继承于RefBase,所以具有RefBase相应的一些特性。

cpp 复制代码
system\core\libutils\include\utils\Thread.h
    
class Thread : virtual public RefBase

而在system/core/libutils/include/utils/RefBase.h中,有一个方法onFirstRef(),根据注释,创建之后就会被调用:

cpp 复制代码
system/core/libutils/include/utils/RefBase.h

class RefBase {
// Invoked after creation of initial strong pointer/reference.
    virtual void            onFirstRef();

Thread类的执行流程

线程创建并启动运行,通过run方法

cpp 复制代码
virtual status_t    run(    const char* name,
                                int32_t priority = PRIORITY_DEFAULT,
                                size_t stack = 0);
cpp 复制代码
/* 首先看run方法,通常走else分支,调用了androidCreateRawThreadEtc
*/
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
    ...

    bool res;
    if (mCanCallJava) {
        res = createThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    } else {
        res = androidCreateRawThreadEtc(_threadLoop,
                this, name, priority, stack, &mThread);
    }
}


int androidCreateRawThreadEtc(android_thread_func_t entryFunction,
                               void *userData,
                               const char* threadName __android_unused,
                               int32_t threadPriority,
                               size_t threadStackSize,
                               android_thread_id_t *threadId)
{
    // 这里可以看到pthread_attr_t,就是之前提到的linux的线程属性
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

...

    errno = 0;
    pthread_t thread; //之前在linux属性中提到的,用于表示线程ID数据结构
    // 这里的pthread_create,更是之前提到的linux中创建线程的方法,而其中的entryFunction,就是线程创建后要执行的方法,而根据之前传入的参数,entryFunction就是_threadLoop
    int result = pthread_create(&thread, &attr,
                    (android_pthread_entry)entryFunction, userData);
    pthread_attr_destroy(&attr);
    ...
}


/*
该函数主要通过调用threadLoop()函数,作为线程执行函数,它是有返回值的方法,而且_threadLoop会根据返回值确定是否继续循环执行的方法,因此基类必要要实现threadLoop函数。
*/
int Thread::_threadLoop(void* user)
{
    ...

    bool first = true;

    do {
        bool result;
        // 第一次时first = true一定会走if分支
        if (first) {
            first = false;
            // 先执行readyToRun,在threadLoop之前
            self->mStatus = self->readyToRun(); 
            result = (self->mStatus == OK);

            if (result && !self->exitPending()) {
                // 然后进入这个if分支,threadLoop()返回结果给result,决定是否退出loop循环,result为true,这个do while循环就会继续
                result = self->threadLoop();
            }
        } else {
            //do while循环的第二次、第三次后续都走这个分支,都会执行threadLoop()
            result = self->threadLoop();
        }

        // establish a scope for mLock
        {
        Mutex::Autolock _l(self->mLock);
        // 当result == false时会进入触发break,退出loop循环。或者mExitPending为true也会触发,销毁线程时调用requestExit()函数,requestExit()就会把mExitPending置位true
        if (result == false || self->mExitPending) {
            self->mExitPending = true;
            self->mRunning = false;
...
            break;
        }
        }

        // Release our strong reference, to let a chance to the thread
        // to die a peaceful death.
        strong.clear();
        // And immediately, re-acquire a strong reference for the next loop
        strong = weak.promote();
    } while(strong != nullptr);

    return 0;
}

线程请求退出方法: 线程销毁,子类最好通过实现requestExit()函数,首先调用Thread类的requestExit()函数,将线程状态mExitPending置为true,然后中断threadLoop,结合前面_threadLoop的do while循环结束条件就知道,退出_threadLoop循环只有两种,要么threadLoop()返回true,要么mExitPending = true

cpp 复制代码
void Thread::requestExit()
{
    Mutex::Autolock _l(mLock);
    mExitPending = true;
}

安卓native堆栈打印

1、进入对应的cpp文件,放开#define LOG_NDEBUG 0注释,且变成#define LOG_NDEBUG 1

2、声明头文件

cpp 复制代码
#include<utils/CallStack.h>
#include<utils/Log.h>

3、调用方法:

cpp 复制代码
CallStack stack;
stack.update();
stack.log("BootAnimation: movie"); 

4、mk或者bp中需要链接以下so库:

复制代码
libutils
libcutils

如果加了上面两个so库,编译还是报错,就再加上 libutilscallstack ,我只加libcutils和libutils编译就会报错,再加上 libutilscallstack 就好了。
cpp 复制代码
frameworks/base/cmds/bootanimation/BootAnimation.cpp

bool BootAnimation::movie() {
    ATRACE_CALL();
    // 以下是新加的堆栈log
    ALOGD("[cmy] BootAnimation: movie start");
    CallStack stack;
    stack.update();
    stack.log("BootAnimation: movie"); 
    if (mAnimation == nullptr) {
        mAnimation = loadAnimation(mZipFileName);
    }

    if (mAnimation == nullptr)
        return false;
    ......
log 复制代码
打印的堆栈log

03-14 10:38:45.257  4450  4453 D BootAnimation: [cmy] BootAnimation: movie start
03-14 10:38:45.266  4450  4453 D BootAnimation: movie:   #00 pc 000000000000fab0  /system/lib64/libbootanimation.so (android::BootAnimation::movie()+112) (BuildId: 2cc5e488eba01c1dfdaa739a3a748677)
03-14 10:38:45.266  4450  4453 D BootAnimation: movie:   #01 pc 000000000000f4bc  /system/lib64/libbootanimation.so (android::BootAnimation::threadLoop()+272) (BuildId: 2cc5e488eba01c1dfdaa739a3a748677)
03-14 10:38:45.266  4450  4453 D BootAnimation: movie:   #02 pc 000000000001003c  /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+416) (BuildId: 974f050a274d2b06051a6a711d1870ac)


根据上方三条native堆栈log,调用顺序是Thread::_threadLoop -> BootAnimation::threadLoop() ->BootAnimation::movie()
但是native堆栈log并不能具体到某一行。


03-14 10:38:45.266  4450  4453 D BootAnimation: movie:   #03 pc 000000000006d8d0  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+196) (BuildId: 64eb5106bc8ae51d575bce9d5c64cec5)
03-14 10:38:45.266  4450  4453 D BootAnimation: movie:   #04 pc 000000000005fd34  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: 64eb5106bc8ae51d575bce9d5c64cec5)
相关推荐
消失的旧时光-19432 小时前
Android 面试高频:JSON 文件、大数据存储与断电安全(从原理到工程实践)
android·面试·json
dalancon3 小时前
VSYNC 信号流程分析 (Android 14)
android
dalancon3 小时前
VSYNC 信号完整流程2
android
dalancon3 小时前
SurfaceFlinger 上帧后 releaseBuffer 完整流程分析
android
用户69371750013844 小时前
不卷AI速度,我卷自己的从容——北京程序员手记
android·前端·人工智能
程序员Android5 小时前
Android 刷新一帧流程trace拆解
android
墨狂之逸才5 小时前
解决 Android/Gradle 编译报错:Comparison method violates its general contract!
android
阿明的小蝴蝶6 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
汪海游龙6 小时前
开源项目 Trending AI 招募 Google Play 内测人员(12 名)
android·github