system/core/libutils/Threads.cpp
Thread::Thread(bool canCallJava)
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thread::mLock"),
mStatus(OK),
mExitPending(false),
mRunning(false)
#if defined(__ANDROID__)
,
mTid(-1)
#endif
{
}
这里有一个很关键的成员变量canCallJava,它很重要,因为在Thread 执行run启动时,代码如下:
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
//...
if (mCanCallJava) {//这里开始有不同
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
//...
return NO_ERROR;
}
mCanCallJava将线程创建函数的逻辑分为两个分支,调用的函数不同。当mCanCallJava为true时,调用createThreadEtc的这个分支,代码如下:
inline bool createThreadEtc(...)
{
return androidCreateThreadEtc(entryFunction, userData, threadName,threadPriority, threadStackSize, threadId) ? true : false;
}
int androidCreateThreadEtc(...)
{
return gCreateThreadFn(entryFunction, userData, threadName,threadPriority, threadStackSize, threadId);
}
继续分析gCreateThreadFn,代码如下:
static android_create_thread_fn gCreateThreadFn = androidCreateRawThreadEtc;
这里gCreateThreadFn是函数指针,初始化时和mCanCallJava为false时使用的是同一个方法。若gCreatThreadFn方法未被初始化,则mCanCallJava为false或者为true都是一样的,只有gCreatThreadFn被初始化成其他的方法,才会有不一样的流程
2 gCreateThreadFn的其他函数指针
代码中有的地方是会修改这个函数指针的指向的,比如在zygote中创建线程, AndroidRuntime调用startReg的地方,就有可能修改这个函数指针,其代码如下所示:
int AndroidRuntime::startReg(JNIEnv*env)
{
//这里会修改函数指针为javaCreateThreadEtc,即不再是androidCreateRawThreadEtc
androidSetCreateThreadFunc((android_create_thread_fn)javaCreateThreadEtc);
return0;
}
这里继续分析代码androidSetCreateThreadFunc的实现,如下所示:
void androidSetCreateThreadFunc(android_create_thread_fn func)
{
gCreateThreadFn = func;
}
如果mCanCallJava为true,则将调用javaCreateThreadEtc(否则会调用androidCreateRawThreadEtc),分析代码,如下所示:
int AndroidRuntime::javaCreateThreadEtc(
android_thread_func_tentryFunction,
void* userData,
const char*threadName,
int32_tthreadPriority,
size_t threadStackSize,
android_thread_id_t* threadId)
{
void**args = (void**) malloc(3 * sizeof(void*));
intresult;
args[0] = (void*) entryFunction;
args[1] = userData;
args[2] = (void*) strdup(threadName);
//调用的还是androidCreateRawThreadEtc,但线程函数却换成了javaThreadShell。
result= androidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args,threadName, threadPriority,threadStackSize, threadId);
returnresult;
}
继续分析javaThreadShell,代码如下:
int AndroidRuntime::javaThreadShell(void* args){
...
int result;
//把这个线程attach到JNI环境中,这样这个线程就可以调用JNI的函数了
if(javaAttachThread(name, &env) != JNI_OK)
return -1;
//调用实际的线程函数干活
result = (*(android_thread_func_t)start)(userData);
//从JNI环境中detach出来。
javaDetachThread();
free(name);
returnresult;
}
它创建的新线程将:
在调用用户线程函数之前会attach到JNI环境中,这样线程函数就可以直接使用JNI函数了。
线程函数退出后,它会从JNI环境中detach,释放一些资源。
同时,进程退出前,dalvik虚拟机会检查是否有attach了,但是最后未detach的线程如果有,则会直接abort(这样并不好),如果关闭JNI check选项,就不会做这个检查,但这个检查和资源释放有关系。建议还是重视JNIcheck。如果直接使用POSIX的线程创建函数,那么凡是使用过attach的,最后就都需要detach!保证资源被正常释放。
线程函数_threadLoop都会被调用,为什么不直接调用用户传入的线程函数呢?分析关键代码androidCreateRawThreadEtc的实现,如下所示:
//这里的entryFunction参数就是_threadLoop
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)
{
//线程初始化操作,start
//线程属性设置
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
#ifdef HAVE_ANDROID_OS /* valgrind is rejecting RT-priority create reqs */
if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) {
thread_data_t* t = new thread_data_t;
t->priority = threadPriority;
t->threadName = threadName ? strdup(threadName) : NULL;
t->entryFunction = entryFunction;
t->userData = userData;
entryFunction = (android_thread_func_t)&thread_data_t::trampoline;
userData = t;
}
#endif
if (threadStackSize) { //线程栈的设置
pthread_attr_setstacksize(&attr, threadStackSize);
}
//线程初始化操作,end
errno = 0;
pthread_t thread;
//创建线程,entryFunction这个参数就是_threadLoop,开始执行_threadLoop方法
int result = pthread_create(&thread, &attr,(android_pthread_entry)entryFunction, userData);
pthread_attr_destroy(&attr);
if (result != 0) {
return 0;
}
if (threadId != NULL) {
*threadId = (android_thread_id_t)thread; // XXX: this is not portable
}
return 1;
}
接下来,分析_threadLoop的实现,代码如下所示:
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast(user);
sp strong(self->mHoldSelf);
wp weak(strong);
self->mHoldSelf.clear();
#ifdef HAVE_ANDROID_OS
self->mTid = gettid();
#endif
bool first = true;
do {
bool result;
if (first) {//这种设计表示只能第一次进来。
first = false;
self->mStatus = self->readyToRun(); //self代表继承Thread类的对象,第一次进来将调用readyToRun,看看是否准备好
result = (self->mStatus == NO_ERROR);
if (result && !self->exitPending()) {
result = self->threadLoop();
}
} else {
result = self->threadLoop();//如果不是第一次进来,则直接调用派生类的threadLoop
//注意:这段代码运行在一个do-while循环中。 这表示即使我们的threadLoop返回了,线程也不一定会退出。
}
//线程退出的条件:
//1)result 为false。如果子类在threadLoop中返回false,线程就可以退出。这属于主动退出的情况,是threadLoop自己不想继续干活了,所以返回false。
//因此,一定不要写错threadLoop的返回值。
//2)mExitPending为true,这个变量可由Thread类的requestExit函数设置,这属于被动退出,因为由外界强制设置了退出条件。
{
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 != 0);
return 0;
}
threadLoop运行在一个循环中,它的返回值可以决定是否退出线程。
int32_t Demo::startMonitor()
{
run("Demo");
}
bool Demo::threadLoop()
{
for (;;) {
...
break;
}
return true;
}
run --> Thread.cpp 中run , 但调用run()函数, 创建线程失败.
原因: thread.cpp 中run 函数在android A13 检测传过来的数据是不是strong point . 如果不是,报错退出. 创建失败, thread_loop 内容无法执行.
A12 能成功, A13 fail .
对比A12 和 A13 的code
A13的接口 mHoldSelf = sp::fromExisting(this);. A12的接口 mHoldSelf =this; .
fromExisting的作用如果一个strong pointer可用,将检索它; 反之终止退出
a12走的通过拷贝构造函数实现的,调用的是incStrong,不要求调用的对象本身必须是sp
a13要求调用者必须是sp,不然就会报错,导致crash
报错log 如下
10-10 02:59:30.656 1987 1987 F DEBUG : Abort message: 'incStrongRequireStrong() called on 0xee0804d0 which isn't already owned'
10-10 02:59:30.656 1987 1987 F DEBUG : r0 00000000 r1 0000071f r2 00000006 r3 fff40a10
10-10 02:59:30.656 1987 1987 F DEBUG : r4 fff40a20 r5 fff40a08 r6 0000071f r7 0000016b
10-10 02:59:30.657 1987 1987 F DEBUG : r8 00000000 r9 ffffffff r10 fff40a10 r11 edf40ddc
10-10 02:59:30.657 1987 1987 F DEBUG : ip 0000071f sp fff409f0 lr ee43de83 pc ee43de96
10-10 02:59:30.657 1987 1987 F DEBUG : backtrace:
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
Mutex::Autolock _l(mLock);
//...
ALOGE(" mHoldSelf start");
// hold a strong reference on ourself
mHoldSelf = sp::fromExisting(this);
// mHoldSelf = this;
ALOGE(" mHoldSelf end");
//...
return NO_ERROR;
}
查看log , 对应code mHoldSelf = sp::fromExisting(this); 导致的.
fromExisting 的函数作用 检测是否有可用strong point, 没有报错退出.
template
sp sp::fromExisting(T* other) {
if (other) {
check_not_on_stack(other);
other->incStrongRequireStrong(other);
sp result;
result.m_ptr = other;
return result;
}
return nullptr;
}
incStrongRequireStrong 和 Abort message: ‘incStrongRequireStrong() called on 0xee0804d0 which isn’t already owned’ 可以对应上了.
这里面有原子操作, 判单是否自增.
const int32_t c = refs->mStrong.fetch_add(1, std::memory_order_relaxed);
LOG_ALWAYS_FATAL_IF(c <= 0 || c == INITIAL_STRONG_VALUE, "incStrongRequireStrong() called on %p which isn't already owned #### c=%d", refs,c);
我失败的原因, 传过来的指针不是strong point 的. 所有 c = INITIAL_STRONG_VALUE (1<<28). 导致报错.
解决办法: 传过来的类的, 设置未sp<> 类型.
参考: https://blog.51cto.com/u_14344871/3370021