注册

Android实战-Native层thread的实现方案

最近阅读Android源码,很多地方都涉及到了线程的概念,比如BootAnimation,应用层的线程倒是略懂一二,Framework的线程却是知之甚少,因此特此记录如下:


Android的Native层thread的实现方案一般有两种:



  • Linux上的posix线程方案
  • Native层面封装的Thread类(用的最多)

posix线程方案


首先创建空文件夹项目-Linux_Thread


其次在Linux_Thread文件夹下创建一个文件thread_posix.c:主要逻辑是在主线程中创建一个子线程mythread,主线程等待子线程执行完毕后,退出进程:


#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <utils/Log.h>

//线程执行逻辑
void *thread_posix_function(void *arg)
{
(void*) arg;
int i;
for(i = 0; i < 40; i++)
{
printf("hello thread i + %d\n", i);
ALOGD("hello thread i + %d\n", i);
sleep(1);
}
return NULL;
}

int main(void)
{

pthread_t mythread;
//创建线程并执行
if(pthread_create(&mythread, NULL, thread_posix_function, NULL))
{
ALOGD("error createing thread");
abort();
}

sleep(1);
//等待mythread线程执行结束
if(pthread_join(mythread, NULL))
{
ALOGD("error joining thread");
abort();
}
ALOGD("hello thread has run end exit\n");
//退出
exit(0);
}

然后在Linux_Thread文件夹下创建项目构建文件Android.mk中将文件编译为可执行文件:


LOCAL_PATH:=${call my-dir}
include ${CLEAR_VARS}
LOCAL_MODULE := linux_thread
LOCAL_SHARED_LIBRARIES := liblog
LOCAL_SRC_FILES := thread_posix.c
LOCAL_PRELINK_MODULE := false
include ${BUILD_EXECUTABLE}

最后确认Linux_Thread项目位于aosp源码文件夹内,开始编译Linux_Thread项目:


source build/envsetup.sh
lunch
make linux_thread

执行成功后,找到输出的可执行文件linux_thread,将文件push到Android设备中去:


adb push linux_thread /data/local/tmp/

注意如果出现报错 Permission denied,需要对文件进行权限修改:


chmod -R 777 linux_thread

开始启动linux_thread:


./linux_thread

image.png


同时也可以通过日志打印输出:


 adb shell locat | grep hello

屏幕截图 2025-05-06 173436.png


以上就是posix线程方案的实现。


Native层的Thread类方案


源码分析


Native层即Framework层的C++部分,Thread的相关代码位置



头文件:system/core/libutils/include/utils/Thread.h


源文件:system/core/libutils/Threads.cpp



# system/core/libutils/include/utils/Thread.h
class Thread : virtual public RefBase
{
public:
explicit Thread(bool canCallJava = true);
virtual ~Thread();

virtual status_t run( const char* name,
int32_t priority = PRIORITY_DEFAULT,
size_t stack = 0)
;

virtual void requestExit();

virtual status_t readyToRun();

status_t requestExitAndWait();

status_t join();

bool isRunning() const;

...
}

Thread继承于RefBase,在构造函数中对canCallJava变量默认赋值为ture,同时声明了一些方法,这些方法都在源文件中实现。


status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
...
if (mRunning) {
// thread already started
return INVALID_OPERATION;
}
...
mRunning = true;

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

if (res == false) {
mStatus = UNKNOWN_ERROR; // something happened!
mRunning = false;
mThread = thread_id_t(-1);
mHoldSelf.clear(); // "this" may have gone away after this.

return UNKNOWN_ERROR;
}
return OK;

// Exiting scope of mLock is a memory barrier and allows new thread to run
}

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)

{
...
errno = 0;
pthread_t thread;
int result = pthread_create(&thread, &attr,
(android_pthread_entry)entryFunction, userData);
pthread_attr_destroy(&attr);
if (result != 0) {
ALOGE("androidCreateRawThreadEtc failed (entry=%p, res=%d, %s)\n"
"(android threadPriority=%d)",
entryFunction, result, strerror(errno), threadPriority);
return 0;
}
...
return 1;
}

int Thread::_threadLoop(void* user)
{
...
bool first = true;

do {
bool result;
//是否第一次执行
if (first) {
first = false;
self->mStatus = self->readyToRun();
result = (self->mStatus == OK);

if (result && !self->exitPending()) {
result = self->threadLoop();
}
} else {
result = self->threadLoop();
}

// establish a scope for mLock
{
Mutex::Autolock _l(self->mLock);
//根据结果来跳出循环
if (result == false || self->mExitPending) {
self->mExitPending = true;
self->mRunning = false;
self->mThread = thread_id_t(-1);
self->mThreadExitedCondition.broadcast();
break;
}
}
strong.clear();
strong = weak.promote();
} while(strong != nullptr);

return 0;
}

在run方法中,mCanCallJava变量一般为false,是在thread创建的时候赋值的。从而进入androidCreateRawThreadEtc()方法创建线程,在此函数中,可以看见还是通过pthread_create()方法创建Linux的posix线程(可以理解为Native的Thread就是对posiz的一个封装);线程运行时回调的函数参数entryFunction值为_threadLoop函数,因此创建的线程会回调到_threadLoop函数中去;_threadLoop函数里则是一个循环逻辑,线程第一次魂环会调用readyToRun()函数,然后再调用threadLoop函数执行线程逻辑,后面就会根据threadLoop执行的结果来判断是否再继续执行下去。


代码练习


头文件MyThread.h


#ifndef _MYTHREAD_H
#define _MYTHREAD_H

#include <utils/threads.h>

namespace android
{
class MyThread: public Thread
{
public:
MyThread();
//创建线程对象就会被调用
virtual void onFirstRef();
//线程创建第一次运行时会被调用
virtual status_t readyToRun();
//根据返回值是否继续执行
virtual bool threadLoop();
virtual void requestExit();

private:
int hasRunCount = 0;
};
}
#endif

源文件MyThread.cpp


#define LOG_TAG "MyThread"

#include <utils/Log.h>
#include "MyThread.h"

namespace android
{
//通过构造函数对mCanCallJava赋值为false
MyThread::MyThread(): Thread(false)
{
ALOGD("MyThread");
}

bool MyThread::threadLoop()
{
ALOGD("threadLoop hasRunCount = %d", hasRunCount);
hasRunCount++;
//计算10次后返回false,表示逻辑结束,线程不需要再继续执行咯
if(hasRunCount == 10)
{
return false;
}
return true;
}

void MyThread::onFirstRef()
{
ALOGD("onFirstRef");
}

status_t MyThread::readyToRun()
{
ALOGD("readyToRun");
return 0;
}

void MyThread::requestExit()
{
ALOGD("requestExit");
}
}

程序入口Main.cpp


#define LOG_TAG "Main"

#include <utils/Log.h>
#include <utils/threads.h>
#include "MyThread.h"

using namespace android;

int main()
{

sp<MyThread> thread = new MyThread;
thread->run("MyThread", PRIORITY_URGENT_DISPLAY);
while(1)
{
if(!thread->isRunning())
{
ALOGD("main thread -> isRunning == false");
break;
}
}

ALOGD("main end");
return 0;
}

项目构建文件Android.mk


LOCAL_PATH:=${call my-dir}
include ${CLEAR_VARS}
LOCAL_MODULE := android_thread
LOCAL_SHARED_LIBRARIES := libandroid_runtime \
libcutils \
libutils \
liblog
LOCAL_SRC_FILES := MyThread.cpp \
Main.cpp \

LOCAL_PRELINK_MODULE := false
include ${BUILD_EXECUTABLE}

项目目录如下:
image.png


通过命令带包得到android_thread可执行文件放入模拟器运行:


屏幕截图 2025-05-08 140036.png


作者:抛空
来源:juejin.cn/post/7501624826286669859

0 个评论

要回复文章请先登录注册