常说:handler把子线程的消息发送给主线程
,这个主线程具体是在哪里创建的?这个问题比较复杂。上篇文章:ActivityThread的main方法在哪里被调用的? 我们得出结论:ActivityThread的main方法是被ZygoteInit.main()方法调用的。这篇文章接着分析主线程的名称"main"是在哪里设置进去的?
答:AndroidRuntime.start
函数里面。在目录/frameworks/base/core/jni/AndroidRuntime.cpp中可以看到start函数完整源码,结合Android系统启动-zygote篇就能知道具体流程。
AndroidRuntime.start
函数有设置线程名称为"main"吗?答:有,Zygote启动虚拟机的时候。
在AndroidRuntime.start
函数中,有调用startVM
/frameworks/base/core/jni/AndroidRuntime.cpp
int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote, bool primary_zygote)
{
JavaVMInitArgs initArgs;
// 前面一大片代码都是都是用来设置ART虚拟机的启动参数的,这里先略过
......
initArgs.version = JNI_VERSION_1_4;
initArgs.options = mOptions.editArray();
initArgs.nOptions = mOptions.size();
initArgs.ignoreUnrecognized = JNI_FALSE;
//重点在这里
if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
ALOGE("JNI_CreateJavaVM failed\n");
return -1;
}
return 0;
}
上面代码中最后调用JNI_CreateJavaVM
来创建虚拟机,这里的JNI_CreateJavaVM
是在/libnativehelper/JniInvocation.cpp
中进行实现的。这里要介绍一个库libart.so
,JNI_CreateJavaVM
和libart.so
的关系参考:基于Android R之ART虚拟机的创建流程。libart.so库中的JNI_CreateJavaVM是在java_vm_ext.cc这个文件中实现的。
/art/runtime/java_vm_ext.cc
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
ScopedTrace trace(__FUNCTION__);
const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
// 虚拟机参数准备,省略具体的过程
// ......
//调用Runtime::Create方法,这里就是进行Runtime对象的创建的
if (!Runtime::Create(options, ignore_unrecognized)) {
return JNI_ERR;
}
// 初始化并加载其他系统动态库,需要加载的动态库都定义在/etc/public.libraryies.txt文件中
android::InitializeNativeLoader();
//获取当前runtime对象并调用Start进行启动
Runtime* runtime = Runtime::Current();
//***********在这里调用runtime.cc文件中的Start()函数
//***********后面详细贴出源代码
bool started = runtime->Start();
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
LOG(WARNING) << "CreateJavaVM failed";
return JNI_ERR;
}
// 保存当前线程和进程的JinEnv和JavaVM对象,JinEnv是每个线程一个,不同线程之间的JinEnv是不同的
//JavaVM是一个进程只有一个
*p_env = Thread::Current()->GetJniEnv();
*p_vm = runtime->GetJavaVM();
return JNI_OK;
}
在Runtime.Start
函数中,调用了 Thread::FinishStartup();
/art/runtime/runtime.cc
bool Runtime::Start() {
......
//这里调用了FinishStartup函数
Thread::FinishStartup();
......
return true;
}
从上面的代码,可以看到Start()
函数调用了FinishStartup
/art/runtime/thread.cc
void Thread::FinishStartup() {
Runtime* runtime = Runtime::Current();
CHECK(runtime->IsStarted());
// Finish attaching the main thread.
ScopedObjectAccess soa(Thread::Current());
//将线程名称设为“main”
soa.Self()->CreatePeer("main", false, runtime->GetMainThreadGroup());
...
}
//CreatePeer函数内部会调用SetThreadName再次修改线程的名称。
void Thread::CreatePeer(const char* name, bool as_daemon, jobject thread_group) {
...
MutableHandle<mirror::String> peer_thread_name(hs.NewHandle(GetThreadName(soa)));
...
if (peer_thread_name.Get() != nullptr) {
SetThreadName(peer_thread_name->ToModifiedUtf8().c_str());
}
}
//SetThreadName函数
void Thread::SetThreadName(const char* name) {
tlsPtr_.name->assign(name);
::art::SetThreadName(name);
Dbg::DdmSendThreadNotification(this, CHUNK_TYPE("THNM"));
}
当虚拟机启动完毕后,zygote的主线程名更改为"main"。
Android中的进程名和线程名
基于Android R之ART虚拟机的创建流程
先创建线程,然后执行ZygoteInit.main函数。通过AndroidRuntime.start
函数源码可以看出,先调用startVm
,startReg
,然后通过反射调用了ZygoteInit.main函数。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.i(TAG, "onCreate: 当前线程名称:" + Thread.currentThread().getName());
Thread.currentThread().setName("yyy");
Log.i(TAG, "onCreate: 修改后线程名称:" + Thread.currentThread().getName());
}
}
输出:
I/MainActivity: onCreate: 当前线程名称:main
I/MainActivity: onCreate: 修改后线程名称:yyy
可以看出:MainActivity的onCreate方法确实在main线程中执行,这个线程名称也可以修改。