安卓线程相关

22 阅读7分钟

linux线程posix实现方案

每个线程都有一个线程ID

/* 用于表示线程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

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

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

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

1. 整体输出结构

-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. 实战分析示例

-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相应的一些特性。

system\core\libutils\include\utils\Thread.h
    
class Thread : virtual public RefBase

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

system/core/libutils/include/utils/RefBase.h

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

Thread类的执行流程

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

virtual status_t    run(    const char* name,
                                int32_t priority = PRIORITY_DEFAULT,
                                size_t stack = 0);
/* 首先看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

void Thread::requestExit()
{
    Mutex::Autolock _l(mLock);
    mExitPending = true;
}

安卓native堆栈打印

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

2、声明头文件

#include<utils/CallStack.h>
#include<utils/Log.h>

3、调用方法:

CallStack stack;
stack.update();
stack.log("BootAnimation: movie"); 

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

libutils
libcutils

如果加了上面两个so库,编译还是报错,就再加上 libutilscallstack ,我只加libcutils和libutils编译就会报错,再加上 libutilscallstack 就好了。
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

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)