## line 490 on property:apexd.status=ready && property:ro.product.cpu.abilist64=* exec_start boringssl_self_test_apex64
service boringssl_self_test32 /system/bin/boringssl_self_test32 reboot_on_failure reboot,boringssl-self-check-failed stdio_to_kmsg # Explicitly specify that boringssl_self_test32 doesn't require any capabilities capabilities user nobody # ...
语法
1 2 3 4 5 6 7 8 9 10
on <trigger> [&& <trigger>]* //设置触发器 <command> <command> //动作触发之后要执行的命令
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main priority -20 user root group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse onrestart write /sys/power/state on # NOTE: If the wakelock name here is changed, then also # update it in SystemSuspend.cpp onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart media.tuner onrestart restart netd onrestart restart wificond task_profiles ProcessCapacityHigh MaxPerformance critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
std::string bootscript = GetProperty("ro.boot.init_rc", ""); if (bootscript.empty()) { parser.ParseConfig("/system/etc/init/hw/init.rc"); if (!parser.ParseConfig("/system/etc/init")) { late_import_paths.emplace_back("/system/etc/init"); } // late_import is available only in Q and earlier release. As we don't // have system_ext in those versions, skip late_import for system_ext. parser.ParseConfig("/system_ext/etc/init"); if (!parser.ParseConfig("/vendor/etc/init")) { late_import_paths.emplace_back("/vendor/etc/init"); } if (!parser.ParseConfig("/odm/etc/init")) { late_import_paths.emplace_back("/odm/etc/init"); } if (!parser.ParseConfig("/product/etc/init")) { late_import_paths.emplace_back("/product/etc/init"); } } else { parser.ParseConfig(bootscript);//开始解析 } }
SectionParser* section_parser = nullptr; int section_start_line = -1; std::vector<std::string> args;
// If we encounter a bad section start, there is no valid parser object to parse the subsequent // sections, so we must suppress errors until the next valid section is found. bool bad_section_found = false;
auto end_section = [&] { bad_section_found = false; if (section_parser == nullptr) return;
for (;;) { switch (next_token(&state)) { case T_EOF: end_section();
for (const auto& [section_name, section_parser] : section_parsers_) { section_parser->EndFile(); }
return; case T_NEWLINE: { state.line++; if (args.empty()) break; // If we have a line matching a prefix we recognize, call its callback and unset any // current section parsers. This is meant for /sys/ and /dev/ line entries for // uevent. auto line_callback = std::find_if( line_callbacks_.begin(), line_callbacks_.end(), [&args](const auto& c) { return android::base::StartsWith(args[0], c.first); }); if (line_callback != line_callbacks_.end()) { end_section();
Result<std::unique_ptr<Service>> Service::MakeTemporaryOneshotService( conststd::vector<std::string>& args) { // Parse the arguments: exec [SECLABEL [UID [GID]*] --] COMMAND ARGS... // SECLABEL can be a - to denote default std::size_t command_arg = 1; for (std::size_t i = 1; i < args.size(); ++i) { if (args[i] == "--") { command_arg = i + 1; break; } } if (command_arg > 4 + NR_SVC_SUPP_GIDS) { return Error() << "exec called with too many supplementary group ids"; }
if (command_arg >= args.size()) { return Error() << "exec called without command"; } std::vector<std::string> str_args(args.begin() + command_arg, args.end());
static Result<void> do_class_start(const BuiltinArguments& args) { // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1. if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false)) return {}; // Starting a class does not start services which are explicitly disabled. // They must be started individually. for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfNotDisabled(); !result.ok()) { LOG(ERROR) << "Could not start service '" << service->name() << "' as part of class '" << args[1] << "': " << result.error(); } } } return {}; }
Result<void> Service::Start() { auto reboot_on_failure = make_scope_guard([this] { if (on_failure_reboot_target_) { trigger_shutdown(*on_failure_reboot_target_); } });
if (is_updatable() && !ServiceList::GetInstance().IsServicesUpdated()) { ServiceList::GetInstance().DelayService(*this); return Error() << "Cannot start an updatable service '" << name_ << "' before configs from APEXes are all loaded. " << "Queued for execution."; }
// Running processes require no additional work --- if they're in the // process of exiting, we've ensured that they will immediately restart // on exit, unless they are ONESHOT. For ONESHOT service, if it's in // stopping status, we just set SVC_RESTART flag so it will get restarted // in Reap(). //如果service已经运行,则不启动 if (flags_ & SVC_RUNNING) { if ((flags_ & SVC_ONESHOT) && disabled) { flags_ |= SVC_RESTART; }
LOG(INFO) << "service '" << name_ << "' requested start, but it is already running (flags: " << flags_ << ")";
// It is not an error to try to start a service that is already running. reboot_on_failure.Disable(); return {}; }
// cgroups_activated is used for communication from the parent to the child // while setsid_finished is used for communication from the child process to // the parent process. These two communication channels are separate because // combining these into a single communication channel would introduce a // race between the Write() calls by the parent and by the child. InterprocessFifo cgroups_activated, setsid_finished; OR_RETURN(cgroups_activated.Initialize()); OR_RETURN(setsid_finished.Initialize());
if (Result<void> result = CheckConsole(); !result.ok()) { return result; } //判断需要启动的service的对应执行文件是否存在,不存在就不启动service struct struct stat sb; if (stat(args_[0].c_str(), &sb) == -1) { flags_ |= SVC_DISABLED; return ErrnoError() << "Cannot find '" << args_[0] << "'"; }
std::string scon; if (!seclabel_.empty()) { scon = seclabel_; } else { auto result = ComputeContextFromExecutable(args_[0]); if (!result.ok()) { return result.error(); } scon = *result; }
if (!mount_namespace_.has_value()) { // remember from which mount namespace the service should start SetMountNamespace(); }
// When the blkio controller is mounted in the v1 hierarchy, NormalIoPriority is // the default (/dev/blkio). When the blkio controller is mounted in the v2 hierarchy, the // NormalIoPriority profile has to be applied explicitly. SetProcessProfiles(proc_attr_.uid, pid_, {"NormalIoPriority"});
if (use_memcg) { ConfigureMemcg(); } }
if (oom_score_adjust_ != DEFAULT_OOM_SCORE_ADJUST) { LmkdRegister(name_, proc_attr_.uid, pid_, oom_score_adjust_); }
if (Result<void> result = cgroups_activated.Write(kCgroupsActivated); !result.ok()) { return Error() << "Sending cgroups activated notification failed: " << result.error(); }
cgroups_activated.Close();
// Call setpgid() from the parent process to make sure that this call has // finished before the parent process calls kill(-pgid, ...). if (!RequiresConsole(proc_attr_)) { if (setpgid(pid, pid) < 0) { switch (errno) { case EACCES: // Child has already performed setpgid() followed by execve(). case ESRCH: // Child process no longer exists. break; default: PLOG(ERROR) << "setpgid() from parent failed"; } } } else { // The Read() call below will return an error if the child is killed. if (Result<uint8_t> result = setsid_finished.Read(); !result.ok() || *result != kSetSidFinished) { if (!result.ok()) { return Error() << "Waiting for setsid() failed: " << result.error(); } else { return Error() << "Waiting for setsid() failed: " << static_cast<uint32_t>(*result) << " <> " << static_cast<uint32_t>(kSetSidFinished); } } }
# Line 1070 # It is recommended to put unnecessary data/ initialization from post-fs-data # to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted wait_for_prop odsign.verification.done 1 # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start statsd start netd start zygote start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported wait_for_prop odsign.verification.done 1 # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start statsd start netd start zygote start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file wait_for_prop odsign.verification.done 1 # A/B update verifier that marks a successful boot. exec_start update_verifier_nonencrypted start statsd start netd start zygote start zygote_secondary
# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter # '--early' can be specified to skip entries with 'latemount'. # /system and /vendor must be mounted by the end of the fs stage, # while /data is optional. trigger fs trigger post-fs
# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter # to only mount entries with 'latemount'. This is needed if '--early' is # specified in the previous mount_all command on the fs stage. # With /system mounted and properties form /system + /factory available, # some services can be started. trigger late-fs
# Now we can mount /data. File encryption requires keymaster to decrypt # /data, which in turn can only be loaded when system properties are present. trigger post-fs-data
# Should be before netd, but after apex, properties and logging is available. trigger load_bpf_programs
# Now we can start zygote for devices with file based encryption trigger zygote-start
# Remove a file to wake up anything waiting for firmware. trigger firmware_mounts_complete
trigger early-boot trigger boot
# Line 1346 on userspace-reboot-resume trigger userspace-reboot-fs-remount trigger post-fs-data trigger zygote-start trigger early-boot trigger boot
class AppRuntime : public AndroidRuntime { public: AppRuntime(char* argBlockStart, const size_t argBlockLength) : AndroidRuntime(argBlockStart, argBlockLength) , mClass(NULL) { }
void setClassNameAndArgs(const String8& className, int argc, char * const *argv) { mClassName = className; for (int i = 0; i < argc; ++i) { mArgs.add(String8(argv[i])); } }
virtual void onVmCreated(JNIEnv* env) { if (mClassName.isEmpty()) { return; // Zygote. Nothing to do here. }
/* * This is a little awkward because the JNI FindClass call uses the * class loader associated with the native method we're executing in. * If called in onStarted (from RuntimeInit.finishInit because we're * launching "am", for example), FindClass would see that we're calling * from a boot class' native method, and so wouldn't look for the class * we're trying to look up in CLASSPATH. Unfortunately it needs to, * because the "am" classes are not boot classes. * * The easiest fix is to call FindClass here, early on before we start * executing boot class Java code and thereby deny ourselves access to * non-boot classes. */ char* slashClassName = toSlashClassName(mClassName.string()); mClass = env->FindClass(slashClassName); if (mClass == NULL) { ALOGE("ERROR: could not find class '%s'\n", mClassName.string()); } free(slashClassName);
/* * Start the Android runtime. This involves starting the virtual machine * and calling the "static void main(String[] args)" method in the class * named by "className". * * Passes the main function two arguments, the class name and the specified * options string. */ voidAndroidRuntime::start(constchar* className, const Vector<String8>& options, bool zygote) { ALOGD(">>>>>> START %s uid %d <<<<<<\n", className != NULL ? className : "(unknown)", getuid());
staticconst String8 startSystemServer("start-system-server"); // Whether this is the primary zygote, meaning the zygote which will fork system server. bool primary_zygote = false;
/* * 'startSystemServer == true' means runtime is obsolete and not run from * init.rc anymore, so we print out the boot start event here. */ for (size_t i = 0; i < options.size(); ++i) { if (options[i] == startSystemServer) { primary_zygote = true; /* track our progress through the boot sequence */ constint LOG_BOOT_PROGRESS_START = 3000; LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); } }
constchar* rootDir = getenv("ANDROID_ROOT"); if (rootDir == NULL) { rootDir = "/system"; if (!hasDir("/system")) { LOG_FATAL("No root directory specified, and /system does not exist."); return; } setenv("ANDROID_ROOT", rootDir, 1); }
constchar* artRootDir = getenv("ANDROID_ART_ROOT"); if (artRootDir == NULL) { LOG_FATAL("No ART directory specified with ANDROID_ART_ROOT environment variable."); return; }
constchar* i18nRootDir = getenv("ANDROID_I18N_ROOT"); if (i18nRootDir == NULL) { LOG_FATAL("No runtime directory specified with ANDROID_I18N_ROOT environment variable."); return; }
constchar* tzdataRootDir = getenv("ANDROID_TZDATA_ROOT"); if (tzdataRootDir == NULL) { LOG_FATAL("No tz data directory specified with ANDROID_TZDATA_ROOT environment variable."); return; }
/* * Register android functions. */ if (startReg(env) < 0) { ALOGE("Unable to register all android natives\n"); return; }
/* * We want to call main() with a String array with arguments in it. * At present we have two arguments, the class name and an option string. * Create an array to hold them. */ jclass stringClass; jobjectArray strArray; jstring classNameStr;
for (size_t i = 0; i < options.size(); ++i) { jstring optionsStr = env->NewStringUTF(options.itemAt(i).string()); assert(optionsStr != NULL); env->SetObjectArrayElement(strArray, i + 1, optionsStr); }
/* * Start VM. This thread becomes the main thread of the VM, and will * not return until the VM exits. */ char* slashClassName = toSlashClassName(className != NULL ? className : ""); jclass startClass = env->FindClass(slashClassName); if (startClass == NULL) { ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); /* keep going */ } else { jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V"); if (startMeth == NULL) { ALOGE("JavaVM unable to find main() in '%s'\n", className); /* keep going */ } else { env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0 if (env->ExceptionCheck()) threadExitUncaughtException(env); #endif } } free(slashClassName);
ALOGD("Shutting down VM\n"); if (mJavaVM->DetachCurrentThread() != JNI_OK) ALOGW("Warning: unable to detach main thread\n"); if (mJavaVM->DestroyJavaVM() != 0) ALOGW("Warning: VM did not shut down cleanly\n"); }
/* * Initialize the VM. * * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread. * If this call succeeds, the VM is ready, and we can start issuing * JNI calls. */ //startVM的前半部分是在处理虚拟机的启动参数,处理完配置参数后,会调用libart.so提供的一个接口JNI_CreateJavaVM函数 if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) { ALOGE("JNI_CreateJavaVM failed\n"); return-1; }
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); if (JavaVMExt::IsBadJniVersion(args->version)) { LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version; return JNI_EVERSION; } RuntimeOptions options; for (int i = 0; i < args->nOptions; ++i) { JavaVMOption* option = &args->options[i]; options.push_back(std::make_pair(std::string(option->optionString), option->extraInfo)); } bool ignore_unrecognized = args->ignoreUnrecognized; //通过Runtime的create方法创建单例的Runtime对象 if (!Runtime::Create(options, ignore_unrecognized)) { return JNI_ERR; }
// When `ART_CRASH_RUNTIME_DELIBERATELY` is defined (which happens only in the // case of a test APEX), we crash the runtime here on purpose, to test the // behavior of rollbacks following a failed ART Mainline Module update. #ifdef ART_CRASH_RUNTIME_DELIBERATELY LOG(FATAL) << "Runtime crashing deliberately for testing purposes."; #endif
// Initialize native loader. This step makes sure we have // everything set up before we start using JNI. android::InitializeNativeLoader();
// Add the JniEnv handler. // TODO Refactor this stuff. java_vm_->AddEnvironmentHook(JNIEnvExt::GetEnvHandler);
Thread::Startup();
// ClassLinker needs an attached thread, but we can't fully attach a thread without creating // objects. We can't supply a thread group yet; it will be fixed later. Since we are the main // thread, we do not get a java peer.
//创建类连接器 if (UNLIKELY(IsAotCompiler())) { class_linker_ = new AotClassLinker(intern_table_); } else { class_linker_ = new ClassLinker( intern_table_, runtime_options.GetOrDefault(Opt::FastClassNotFoundException)); } if (GetHeap()->HasBootImageSpace()) { //初始化类连接器 bool result = class_linker_->InitFromBootImage(&error_msg); if (!result) { LOG(ERROR) << "Could not initialize from image: " << error_msg; returnfalse; } if (kIsDebugBuild) { for (auto image_space : GetHeap()->GetBootImageSpaces()) { image_space->VerifyImageAllocations(); } } { ScopedTrace trace2("AddImageStringsToTable"); for (gc::space::ImageSpace* image_space : heap_->GetBootImageSpaces()) { GetInternTable()->AddImageStringsToTable(image_space, VoidFunctor()); } }
constsize_t total_components = gc::space::ImageSpace::GetNumberOfComponents( ArrayRef<gc::space::ImageSpace* const>(heap_->GetBootImageSpaces())); if (total_components != GetBootClassPath().size()) { // The boot image did not contain all boot class path components. Load the rest. CHECK_LT(total_components, GetBootClassPath().size()); size_t start = total_components; DCHECK_LT(start, GetBootClassPath().size()); std::vector<std::unique_ptr<const DexFile>> extra_boot_class_path; if (runtime_options.Exists(Opt::BootClassPathDexList)) { extra_boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList)); } else { ArrayRef<constint> bcp_fds = start < GetBootClassPathFds().size() ? ArrayRef<constint>(GetBootClassPathFds()).SubArray(start) : ArrayRef<constint>(); OpenBootDexFiles(ArrayRef<conststd::string>(GetBootClassPath()).SubArray(start), ArrayRef<conststd::string>(GetBootClassPathLocations()).SubArray(start), bcp_fds, &extra_boot_class_path); } class_linker_->AddExtraBootDexFiles(self, std::move(extra_boot_class_path)); } if (IsJavaDebuggable() || jit_options_->GetProfileSaverOptions().GetProfileBootClassPath()) { // Deoptimize the boot image if debuggable as the code may have been compiled non-debuggable. // Also deoptimize if we are profiling the boot class path. ScopedThreadSuspension sts(self, ThreadState::kNative); ScopedSuspendAll ssa(__FUNCTION__); DeoptimizeBootImage(); } } else { std::vector<std::unique_ptr<const DexFile>> boot_class_path; if (runtime_options.Exists(Opt::BootClassPathDexList)) { boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList)); } else { OpenBootDexFiles(ArrayRef<conststd::string>(GetBootClassPath()), ArrayRef<conststd::string>(GetBootClassPathLocations()), ArrayRef<constint>(GetBootClassPathFds()), &boot_class_path); } if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) { LOG(ERROR) << "Could not initialize without image: " << error_msg; returnfalse; }
// TODO: Should we move the following to InitWithoutImage? SetInstructionSet(instruction_set_); for (uint32_t i = 0; i < kCalleeSaveSize; i++) { CalleeSaveType type = CalleeSaveType(i); if (!HasCalleeSaveMethod(type)) { SetCalleeSaveMethod(CreateCalleeSaveMethod(), type); } } }
// Now that the boot image space is set, cache the boot classpath checksums, // to be used when validating oat files. ArrayRef<gc::space::ImageSpace* const> image_spaces(GetHeap()->GetBootImageSpaces()); ArrayRef<const DexFile* const> bcp_dex_files(GetClassLinker()->GetBootClassPath()); boot_class_path_checksums_ = gc::space::ImageSpace::GetBootClassPathChecksums(image_spaces, bcp_dex_files);
// TODO: Remove this in a follow up CL. This isn't used anywhere. Trace::SetDefaultClockSource(runtime_options.GetOrDefault(Opt::ProfileClock));
if (GetHeap()->HasBootImageSpace()) { const ImageHeader& image_header = GetHeap()->GetBootImageSpaces()[0]->GetImageHeader(); ObjPtr<mirror::ObjectArray<mirror::Object>> boot_image_live_objects = ObjPtr<mirror::ObjectArray<mirror::Object>>::DownCast( image_header.GetImageRoot(ImageHeader::kBootImageLiveObjects)); pre_allocated_OutOfMemoryError_when_throwing_exception_ = GcRoot<mirror::Throwable>( boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingException)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_throwing_exception_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_OutOfMemoryError_when_throwing_oome_ = GcRoot<mirror::Throwable>( boot_image_live_objects->Get(ImageHeader::kOomeWhenThrowingOome)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_throwing_oome_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_OutOfMemoryError_when_handling_stack_overflow_ = GcRoot<mirror::Throwable>( boot_image_live_objects->Get(ImageHeader::kOomeWhenHandlingStackOverflow)->AsThrowable()); DCHECK(pre_allocated_OutOfMemoryError_when_handling_stack_overflow_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/OutOfMemoryError;")); pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>( boot_image_live_objects->Get(ImageHeader::kNoClassDefFoundError)->AsThrowable()); DCHECK(pre_allocated_NoClassDefFoundError_.Read()->GetClass() ->DescriptorEquals("Ljava/lang/NoClassDefFoundError;")); } else { // Pre-allocate an OutOfMemoryError for the case when we fail to // allocate the exception to be thrown. CreatePreAllocatedException(self, this, &pre_allocated_OutOfMemoryError_when_throwing_exception_, "Ljava/lang/OutOfMemoryError;", "OutOfMemoryError thrown while trying to throw an exception; " "no stack trace available"); // Pre-allocate an OutOfMemoryError for the double-OOME case. CreatePreAllocatedException(self, this, &pre_allocated_OutOfMemoryError_when_throwing_oome_, "Ljava/lang/OutOfMemoryError;", "OutOfMemoryError thrown while trying to throw OutOfMemoryError; " "no stack trace available"); // Pre-allocate an OutOfMemoryError for the case when we fail to // allocate while handling a stack overflow. CreatePreAllocatedException(self, this, &pre_allocated_OutOfMemoryError_when_handling_stack_overflow_, "Ljava/lang/OutOfMemoryError;", "OutOfMemoryError thrown while trying to handle a stack overflow; " "no stack trace available");
// Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class // ahead of checking the application's class loader. CreatePreAllocatedException(self, this, &pre_allocated_NoClassDefFoundError_, "Ljava/lang/NoClassDefFoundError;", "Class not found using the boot class loader; " "no stack trace available"); }
// Class-roots are setup, we can now finish initializing the JniIdManager. GetJniIdManager()->Init(self);
InitMetrics();
// Runtime initialization is largely done now. // We load plugins first since that can modify the runtime state slightly. // Load all plugins { // The init method of plugins expect the state of the thread to be non runnable. ScopedThreadSuspension sts(self, ThreadState::kNative); for (auto& plugin : plugins_) { std::string err; if (!plugin.Load(&err)) { LOG(FATAL) << plugin << " failed to load: " << err; } } }
new gc::Heap(),创建Heap对象,这是虚拟机管理对内存的起点
new JavaVmExt(),创建Java虚拟机实例
Thread::attach(),attach主线程
创建ClassLinker
初始化Classlinker,成功attach到runtime环境后,创建ClassLinker实例负责管理java class
// Run the action that is acting on the peer. if (!peer_action(self)) { runtime->GetThreadList()->Unregister(self, should_run_callbacks); // Unregister deletes self, no need to do this here. return nullptr; }
/* * Register android native functions with the VM. */ /*static*/intAndroidRuntime::startReg(JNIEnv* env) { ATRACE_NAME("RegisterAndroidNatives"); /* * This hook causes all future threads created in this process to be * attached to the JavaVM. (This needs to go away in favor of JNI * Attach calls.) */ androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc);
ALOGV("--- registering native functions ---\n");
/* * Every "register" function calls one or more things that return * a local reference (e.g. FindClass). Because we haven't really * started the VM yet, they're all getting stored in the base frame * and never released. Use Push/Pop to manage the storage. */ env->PushLocalFrame(200);
//line 658 status_tThread::run(constchar* name, int32_t priority, size_tstack) { LOG_ALWAYS_FATAL_IF(name == nullptr, "thread name not provided to Thread::run");
Mutex::Autolock _l(mLock);
if (mRunning) { // thread already started return INVALID_OPERATION; }
// reset status and exitPending to their default value, so we can // try again after an error happened (either below, or in readyToRun()) mStatus = OK; mExitPending = false; mThread = thread_id_t(-1);
// hold a strong reference on ourself mHoldSelf = sp<Thread>::fromExisting(this);
mRunning = true;
bool res;
//android native层有两种Thread的创建方式 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; }
// Do not refer to mStatus here: The thread is already running (may, in fact // already have exited with a valid mStatus result). The OK indication // here merely indicates successfully starting the thread and does not // imply successful termination/execution. return OK;
// Exiting scope of mLock is a memory barrier and allows new thread to run }
#if defined(__ANDROID__) /* valgrind is rejecting RT-priority create reqs */ if (threadPriority != PRIORITY_DEFAULT || threadName != NULL) { // Now that the pthread_t has a method to find the associated // android_thread_id_t (pid) from pthread_t, it would be possible to avoid // this trampoline in some cases as the parent could set the properties // for the child. However, there would be a race condition because the // child becomes ready immediately, and it doesn't work for the name. // prctl(PR_SET_NAME) only works for self; prctl(PR_SET_THREAD_NAME) was // proposed but not yet accepted. 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); }
// Note that *threadID is directly available to the parent only, as it is // assigned after the child starts. Use memory barrier / lock if the child // or other threads also need access. if (threadId != nullptr) { *threadId = (android_thread_id_t)thread; // XXX: this is not portable } return1; }
/* * Code written in the Java Programming Language calls here from main(). */ staticvoidcom_android_internal_os_RuntimeInit_nativeFinishInit(JNIEnv* env, jobject clazz) { gCurRuntime->onStarted(); }
/** * This is the entry point for a Zygote process. It creates the Zygote server, loads resources, * and handles other tasks related to preparing the process for forking into applications. * * This process is started with a nice value of -20 (highest priority). All paths that flow * into new processes are required to either set the priority to the default value or terminate * before executing any non-system code. The native side of this occurs in SpecializeCommon, * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess, * ZygoteConnection.handleChildProc, and Zygote.childMain. * * @param argv Command line arguments used to specify the Zygote's configuration. */ @UnsupportedAppUsage publicstaticvoidmain(String[] argv) { ZygoteServerzygoteServer=null;
// Mark zygote start. This ensures that thread creation will throw // an error. ZygoteHooks.startZygoteNoThreadCreation();
// Zygote goes into its own process group. try { Os.setpgid(0, 0); } catch (ErrnoException ex) { thrownewRuntimeException("Failed to setpgid(0,0)", ex); }
Runnable caller; try { // Store now for StatsLogging later. finallongstartTime= SystemClock.elapsedRealtime(); finalbooleanisRuntimeRestarted="1".equals( SystemProperties.get("sys.boot_completed"));
finalbooleanisPrimaryZygote= zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME); if (!isRuntimeRestarted) { if (isPrimaryZygote) { FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__ZYGOTE_INIT_START, startTime); } elseif (zygoteSocketName.equals(Zygote.SECONDARY_SOCKET_NAME)) { FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SECONDARY_ZYGOTE_INIT_START, startTime); } }
if (abiList == null) { thrownewRuntimeException("No ABI list supplied."); }
// In some configurations, we avoid preloading resources and classes eagerly. // In such cases, we will preload things prior to our first fork. // 在有些情况下我们需要在第一个fork之前进行预加载资源 if (!enableLazyPreload) { bootTimingsTraceLog.traceBegin("ZygotePreload"); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START, SystemClock.uptimeMillis()); preload(bootTimingsTraceLog); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload }
// Do an initial gc to clean up after startup bootTimingsTraceLog.traceBegin("PostZygoteInitGC"); gcAndFinalize(); bootTimingsTraceLog.traceEnd(); // PostZygoteInitGC
if (startSystemServer) { Runnabler= forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the // child (system_server) process. if (r != null) { r.run(); return; } }
// The select loop returns early in the child process after a fork and // loops forever in the zygote. caller = zygoteServer.runSelectLoop(abiList); } catch (Throwable ex) { Log.e(TAG, "System zygote died with fatal exception", ex); throw ex; } finally { if (zygoteServer != null) { zygoteServer.closeServerSocket(); } }
// We're in the child process and have exited the select loop. Proceed to execute the // command. if (caller != null) { caller.run(); } }
// line 137
staticvoidpreload(TimingsTraceLog bootTimingsTraceLog) { Log.d(TAG, "begin preload"); bootTimingsTraceLog.traceBegin("BeginPreload"); beginPreload(); bootTimingsTraceLog.traceEnd(); // BeginPreload bootTimingsTraceLog.traceBegin("PreloadClasses"); //加载指定的类到内存并且初始化,使用的Class.forName(class,ture,null)的方式 preloadClasses(); bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders"); cacheNonBootClasspathClassLoaders(); bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders bootTimingsTraceLog.traceBegin("PreloadResources"); //加载Android 通用的资源,比如drawable preloadResources(); bootTimingsTraceLog.traceEnd(); // PreloadResources Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadAppProcessHALs"); nativePreloadAppProcessHALs(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadGraphicsDriver"); maybePreloadGraphicsDriver(); Trace.traceEnd(Trace.TRACE_TAG_DALVIK); preloadSharedLibraries(); preloadTextResources(); // Ask the WebViewFactory to do any initialization that must run in the zygote process, // for memory sharing purposes. WebViewFactory.prepareWebViewInZygote(); endPreload(); warmUpJcaProviders(); Log.d(TAG, "end preload");
/** * Runs several special GCs to try to clean up a few generations of * softly- and final-reachable objects, along with any other garbage. * This is only useful just before a fork(). * * @hide */ @SystemApi(client = MODULE_LIBRARIES) publicstaticvoidgcAndFinalize() { finalVMRuntimeruntime= VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote, * which doesn't have a HeapWorker thread. */ System.gc(); runtime.runFinalizationSync(); cleanLocaleCaches(); System.gc(); }
/** * Prepare the arguments and forks for the system server process. * * @return A {@code Runnable} that provides an entrypoint into system_server code in the child * process; {@code null} in the parent. */ privatestatic Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) { longcapabilities= posixCapabilitiesAsBits( OsConstants.CAP_IPC_LOCK, OsConstants.CAP_KILL, OsConstants.CAP_NET_ADMIN, OsConstants.CAP_NET_BIND_SERVICE, OsConstants.CAP_NET_BROADCAST, OsConstants.CAP_NET_RAW, OsConstants.CAP_SYS_MODULE, OsConstants.CAP_SYS_NICE, OsConstants.CAP_SYS_PTRACE, OsConstants.CAP_SYS_TIME, OsConstants.CAP_SYS_TTY_CONFIG, OsConstants.CAP_WAKE_ALARM, OsConstants.CAP_BLOCK_SUSPEND ); /* Containers run without some capabilities, so drop any caps that are not available. */ StructCapUserHeaderheader=newStructCapUserHeader( OsConstants._LINUX_CAPABILITY_VERSION_3, 0); StructCapUserData[] data; try { data = Os.capget(header); } catch (ErrnoException ex) { thrownewRuntimeException("Failed to capget()", ex); } capabilities &= Integer.toUnsignedLong(data[0].effective) | (Integer.toUnsignedLong(data[1].effective) << 32);
/* Hardcoded command line to start the system server */ //启动SystemServer的命令行,部分参数写死 String[] args = { "--setuid=1000", "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023," + "1024,1032,1065,3001,3002,3003,3005,3006,3007,3009,3010,3011,3012", "--capabilities=" + capabilities + "," + capabilities, "--nice-name=system_server", "--runtime-args", "--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT, "com.android.server.SystemServer", }; ZygoteArguments parsedArgs;
if (Zygote.nativeSupportsMemoryTagging()) { Stringmode= SystemProperties.get("persist.arm64.memtag.system_server", ""); if (mode.isEmpty()) { /* The system server has ASYNC MTE by default, in order to allow * system services to specify their own MTE level later, as you * can't re-enable MTE once it's disabled. */ mode = SystemProperties.get("persist.arm64.memtag.default", "async"); } if (mode.equals("async")) { parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_ASYNC; } elseif (mode.equals("sync")) { parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_SYNC; } elseif (!mode.equals("off")) { /* When we have an invalid memory tag level, keep the current level. */ parsedArgs.mRuntimeFlags |= Zygote.nativeCurrentTaggingLevel(); Slog.e(TAG, "Unknown memory tag level for the system server: \"" + mode + "\""); } } elseif (Zygote.nativeSupportsTaggedPointers()) { /* Enable pointer tagging in the system server. Hardware support for this is present * in all ARMv8 CPUs. */ parsedArgs.mRuntimeFlags |= Zygote.MEMORY_TAG_LEVEL_TBI; }
/* Enable gwp-asan on the system server with a small probability. This is the same * policy as applied to native processes and system apps. */ parsedArgs.mRuntimeFlags |= Zygote.GWP_ASAN_LEVEL_LOTTERY;
if (shouldProfileSystemServer()) { parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER; }
/** * Finish remaining work for the newly forked system server process. */ privatestatic Runnable handleSystemServerProcess(ZygoteArguments parsedArgs) { // set umask to 0077 so new files and directories will default to owner-only permissions. Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.mNiceName != null) { Process.setArgV0(parsedArgs.mNiceName); }
finalStringsystemServerClasspath= Os.getenv("SYSTEMSERVERCLASSPATH"); if (systemServerClasspath != null) { // Capturing profiles is only supported for debug or eng builds since selinux normally // prevents it. if (shouldProfileSystemServer() && (Build.IS_USERDEBUG || Build.IS_ENG)) { try { Log.d(TAG, "Preparing system server profile"); finalStringstandaloneSystemServerJars= Os.getenv("STANDALONE_SYSTEMSERVER_JARS"); finalStringsystemServerPaths= standaloneSystemServerJars != null ? String.join(":", systemServerClasspath, standaloneSystemServerJars) : systemServerClasspath; //将SYSTEMSERVERCLASSPATH中的AppInfo加载到VM中 prepareSystemServerProfile(systemServerPaths); } catch (Exception e) { Log.wtf(TAG, "Failed to set up system server profile", e); } } }
if (parsedArgs.mInvokeWith != null) { String[] args = parsedArgs.mRemainingArgs; // If we have a non-null system server class path, we'll have to duplicate the // existing arguments and append the classpath to it. ART will handle the classpath // correctly when we exec a new process.
/** * Invokes a static "main(argv[]) method on class "className". * Converts various failing exceptions into RuntimeExceptions, with * the assumption that they will then cause the VM instance to exit. * * @param className Fully-qualified class name * @param argv Argument vector for main() * @param classLoader the classLoader to load {@className} with */ protectedstatic Runnable findStaticMain(String className, String[] argv, ClassLoader classLoader) { Class<?> cl;
try { cl = Class.forName(className, true, classLoader); } catch (ClassNotFoundException ex) { thrownewRuntimeException( "Missing class when invoking static main " + className, ex); }
Method m; try { m = cl.getMethod("main", newClass[] { String[].class }); } catch (NoSuchMethodException ex) { thrownewRuntimeException( "Missing static main on " + className, ex); } catch (SecurityException ex) { thrownewRuntimeException( "Problem getting static main on " + className, ex); }
intmodifiers= m.getModifiers(); if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { thrownewRuntimeException( "Main method is not public and static on " + className); }
/* * This throw gets caught in ZygoteInit.main(), which responds * by invoking the exception's run() method. This arrangement * clears up all the stack frames that were required in setting * up the process. */ returnnewMethodAndArgsCaller(m, argv); }
/** * Helper class which holds a method and arguments and can call them. This is used as part of * a trampoline to get rid of the initial process setup stack frames. */ staticclassMethodAndArgsCallerimplementsRunnable { /** method to call */ privatefinal Method mMethod;
/** * System Context to be used for UI. This Context has resources that can be themed. * Make sure that the created system UI context shares the same LoadedApk as the system context. * @param systemContext The system context which created by * {@link #createSystemContext(ActivityThread)}. * @param displayId The ID of the display where the UI is shown. */ static ContextImpl createSystemUiContext(ContextImpl systemContext, int displayId) { finalWindowTokenClienttoken=newWindowTokenClient(); finalContextImplcontext= systemContext.createWindowContextBase(token, displayId); token.attachContext(context); token.attachToDisplayContent(displayId); context.mContextType = CONTEXT_TYPE_SYSTEM_OR_SYSTEM_UI; context.mOwnsToken = true;
// Clamp display ID to DEFAULT_DISPLAY if it is INVALID_DISPLAY. displayId = (displayId != Display.INVALID_DISPLAY) ? displayId : Display.DEFAULT_DISPLAY;
// Create the base resources for which all configuration contexts for this Activity // will be rebased upon. context.setResources(resourcesManager.createBaseTokenResources(activityToken, packageInfo.getResDir(), splitDirs, packageInfo.getOverlayDirs(), packageInfo.getOverlayPaths(), packageInfo.getApplicationInfo().sharedLibraryFiles, displayId, overrideConfiguration, compatInfo, classLoader, packageInfo.getApplication() == null ? null : packageInfo.getApplication().getResources().getLoaders())); context.setDisplay(resourcesManager.getAdjustedDisplay( displayId, context.getResources())); return context; }
// Record the process start information in sys props. SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount)); SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime)); SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));
// Set the device's time zone (a system property) if it is not set or is invalid. SystemTimeZone.initializeTimeZoneSettingsIfRequired();
// If the system has "persist.sys.language" and friends set, replace them with // "persist.sys.locale". Note that the default locale at this point is calculated // using the "-Duser.locale" command line flag. That flag is usually populated by // AndroidRuntime using the same set of system properties, but only the system_server // and system apps are allowed to set them. // // NOTE: Most changes made here will need an equivalent change to // core/jni/AndroidRuntime.cpp if (!SystemProperties.get("persist.sys.language").isEmpty()) { finalStringlanguageTag= Locale.getDefault().toLanguageTag();
// The system server should never make non-oneway calls Binder.setWarnOnBlocking(true); // The system server should always load safe labels PackageItemInfo.forceSafeLabels();
// Default to FULL within the system server. SQLiteGlobal.sDefaultSyncMode = SQLiteGlobal.SYNC_MODE_FULL;
// Deactivate SQLiteCompatibilityWalFlags until settings provider is initialized SQLiteCompatibilityWalFlags.init(null);
// Here we go! Slog.i(TAG, "Entered the Android system server!"); finallonguptimeMillis= SystemClock.elapsedRealtime(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis); if (!mRuntimeRestart) { FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, FrameworkStatsLog .BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_INIT_START, uptimeMillis); }
// In case the runtime switched since last boot (such as when // the old runtime was removed in an OTA), set the system // property so that it is in sync. We can't do this in // libnativehelper's JniInvocation::Init code where we already // had to fallback to a different runtime because it is // running as root and we need to be the system user to set // the property. http://b/11463182 SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Mmmmmm... more memory! VMRuntime.getRuntime().clearGrowthLimit();
// Some devices rely on runtime fingerprint generation, so make sure // we've defined it before booting further. Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without // explicitly specifying a user. Environment.setUserRequired(true);
// Within the system server, any incoming Bundles should be defused // to avoid throwing BadParcelableException. BaseBundle.setShouldDefuse(true);
// Within the system server, when parceling exceptions, include the stack trace Parcel.setStackTraceParceling(true);
// Ensure binder calls into the system always run at foreground priority. BinderInternal.disableBackgroundScheduling(true);
// Increase the number of binder threads in system_server BinderInternal.setMaxThreads(sMaxBinderThreads);
// Prepare the main looper thread (this thread). android.os.Process.setThreadPriority( android.os.Process.THREAD_PRIORITY_FOREGROUND); android.os.Process.setCanSelfBackground(false); Looper.prepareMainLooper(); Looper.getMainLooper().setSlowLogThresholdMs( SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
// Sets the dumper service ServiceManager.addService("system_server_dumper", mDumper); mDumper.addDumpable(this);
// Create the system service manager. mSystemServiceManager = newSystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(mRuntimeRestart, mRuntimeStartElapsedTime, mRuntimeStartUptime); mDumper.addDumpable(mSystemServiceManager);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); // Prepare the thread pool for init tasks that can be parallelized SystemServerInitThreadPooltp= SystemServerInitThreadPool.start(); mDumper.addDumpable(tp);
// Load preinstalled system fonts for system server, so that WindowManagerService, etc // can start using Typeface. Note that fonts are required not only for text rendering, // but also for some text operations (e.g. TextUtils.makeSafeForPresentation()). if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) { Typeface.loadPreinstalledSystemFontMap(); }
// Attach JVMTI agent if this is a debuggable build and the system property is set. if (Build.IS_DEBUGGABLE) { // Property is of the form "library_path=parameters". StringjvmtiAgent= SystemProperties.get("persist.sys.dalvik.jvmtiagent"); if (!jvmtiAgent.isEmpty()) { intequalIndex= jvmtiAgent.indexOf('='); StringlibraryPath= jvmtiAgent.substring(0, equalIndex); StringparameterList= jvmtiAgent.substring(equalIndex + 1, jvmtiAgent.length()); // Attach the agent. try { Debug.attachJvmtiAgent(libraryPath, parameterList, null); } catch (Exception e) { Slog.e("System", "*************************************************"); Slog.e("System", "********** Failed to load jvmti plugin: " + jvmtiAgent); } } } } finally { t.traceEnd(); // InitBeforeStartServices }
// Setup the default WTF handler RuntimeInit.setDefaultApplicationWtfHandler(SystemServer::handleEarlySystemWtf);
// Start services. try { t.traceBegin("StartServices"); startBootstrapServices(t); startCoreServices(t); startOtherServices(t); startApexServices(t); // Only update the timeout after starting all the services so that we use // the default timeout to start system server. updateWatchdogTimeout(t); } catch (Throwable ex) { Slog.e("System", "******************************************"); Slog.e("System", "************ Failure starting system services", ex); throw ex; } finally { t.traceEnd(); // StartServices }
StrictMode.initVmDefaults(null);
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) { finallonguptimeMillis= SystemClock.elapsedRealtime(); FrameworkStatsLog.write(FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED, FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__SYSTEM_SERVER_READY, uptimeMillis); finallongmaxUptimeMillis=60 * 1000; if (uptimeMillis > maxUptimeMillis) { Slog.wtf(SYSTEM_SERVER_TIMING_TAG, "SystemServer init took too long. uptimeMillis=" + uptimeMillis); } }
/** * Special method to start the system server process. In addition to the * common actions performed in forkAndSpecialize, the pid of the child * process is recorded such that the death of the child process will cause * zygote to exit. * * @param uid the UNIX uid that the new process should setuid() to after * fork()ing and and before spawning any threads. * @param gid the UNIX gid that the new process should setgid() to after * fork()ing and and before spawning any threads. * @param gids null-ok; a list of UNIX gids that the new process should * setgroups() to after fork and before spawning any threads. * @param runtimeFlags bit flags that enable ART features. * @param rlimits null-ok an array of rlimit tuples, with the second * dimension having a length of 3 and representing * (resource, rlim_cur, rlim_max). These are set via the posix * setrlimit(2) call. * @param permittedCapabilities argument for setcap() * @param effectiveCapabilities argument for setcap() * * @return 0 if this is the child, pid of the child * if this is the parent, or -1 on error. */ staticintforkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork();
// Set the Java Language thread priority to the default value for new apps. Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
ZygoteHooks.postForkCommon(); return pid; }
privatestaticnativeintnativeForkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
if (gUsapPoolEventFD != -1) { fds_to_close.push_back(gUsapPoolEventFD); fds_to_ignore.push_back(gUsapPoolEventFD); }
if (gSystemServerSocketFd != -1) { fds_to_close.push_back(gSystemServerSocketFd); fds_to_ignore.push_back(gSystemServerSocketFd); }
pid_t pid = zygote::ForkCommon(env, true, fds_to_close, fds_to_ignore, true); if (pid == 0) { // System server prcoess does not need data isolation so no need to // know pkg_data_info_list. SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true, false, nullptr, nullptr, /* is_top_app= */false, /* pkg_data_info_list */ nullptr, /* allowlisted_data_info_list */ nullptr, false, false); } elseif (pid > 0) { // The zygote process checks whether the child process has died or not. ALOGI("System server process %d has been created", pid); gSystemServerPid = pid; // There is a slight window that the system server process has crashed // but it went unnoticed because we haven't published its pid yet. So // we recheck here just to make sure that all is well. // WNOHANG会让waitpid立即返回,这里只是为预防上面的赋值语句没有完成之前SystemServer就crash了
int status; if (waitpid(pid, &status, WNOHANG) == pid) { ALOGE("System server process %d has died. Restarting Zygote!", pid); RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!"); }
if (UsePerAppMemcg()) { // Assign system_server to the correct memory cgroup. // Not all devices mount memcg so check if it is mounted first // to avoid unnecessarily printing errors and denials in the logs. if (!SetTaskProfiles(pid, std::vector<std::string>{"SystemMemoryProcess"})) { ALOGE("couldn't add process %d into system memcg group", pid); } } } return pid; }
// line 2251 // Utility routine to fork a process from the zygote. NO_STACK_PROTECTOR pid_tzygote::ForkCommon(JNIEnv* env, bool is_system_server, conststd::vector<int>& fds_to_close, conststd::vector<int>& fds_to_ignore, bool is_priority_fork, bool purge) { SetSignalHandlers();
// Curry a failure function. auto fail_fn = std::bind(zygote::ZygoteFailure, env, is_system_server ? "system_server" : "zygote", nullptr, _1);
// Temporarily block SIGCHLD during forks. The SIGCHLD handler might // log, which would result in the logging FDs we close being reopened. // This would cause failures because the FDs are not allowlisted. // // Note that the zygote process is single threaded at this point. BlockSignal(SIGCHLD, fail_fn);
// Close any logging related FDs before we start evaluating the list of // file descriptors. __android_log_close(); AStatsSocket_close();
// If this is the first fork for this zygote, create the open FD table, // verifying that files are of supported type and allowlisted. Otherwise (not // the first fork), check that the open files have not changed. Newly open // files are not expected, and will be disallowed in the future. Currently // they are allowed if they pass the same checks as in the // FileDescriptorTable::Create() above. if (gOpenFdTable == nullptr) { gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, fail_fn); } else { gOpenFdTable->Restat(fds_to_ignore, fail_fn); }
if (purge) { // Purge unused native memory in an attempt to reduce the amount of false // sharing with the child process. By reducing the size of the libc_malloc // region shared with the child process we reduce the number of pages that // transition to the private-dirty state when malloc adjusts the meta-data // on each of the pages it is managing after the fork. if (mallopt(M_PURGE_ALL, 0) != 1) { mallopt(M_PURGE, 0); } }
pid_t pid = fork();
if (pid == 0) { if (is_priority_fork) { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); } else { setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); }
#if defined(__BIONIC__) && !defined(NO_RESET_STACK_PROTECTOR) // Reset the stack guard for the new process. android_reset_stack_guards(); #endif
// The child process. PreApplicationInit();
// Clean up any descriptors which must be closed immediately DetachDescriptors(env, fds_to_close, fail_fn);
// Invalidate the entries in the USAP table. ClearUsapTable();
// Re-open all remaining open file descriptors so that they aren't shared // with the zygote across a fork. gOpenFdTable->ReopenOrDetach(fail_fn);
// Turn fdsan back on. android_fdsan_set_error_level(fdsan_error_level);
// Reset the fd to the unsolicited zygote socket gSystemServerSocketFd = -1; } elseif (pid == -1) { ALOGE("Failed to fork child process: %s (%d)", strerror(errno), errno); } else { ALOGD("Forked child process %d", pid); }
// We blocked SIGCHLD prior to a fork, we unblock it here. UnblockSignal(SIGCHLD, fail_fn);
return pid; }
// This signal handler is for zygote mode, since the zygote must reap its children NO_STACK_PROTECTOR staticvoidSigChldHandler(int/*signal_number*/, siginfo_t* info, void* /*ucontext*/) { pid_t pid; int status; int64_t usaps_removed = 0;
// It's necessary to save and restore the errno during this function. // Since errno is stored per thread, changing it here modifies the errno // on the thread on which this signal handler executes. If a signal occurs // between a call and an errno check, it's possible to get the errno set // here. // See b/23572286 for extra information. int saved_errno = errno;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { // Notify system_server that we received a SIGCHLD sendSigChildStatus(pid, info->si_uid, status); // Log process-death status that we care about. if (WIFEXITED(status)) { async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, "Process %d exited cleanly (%d)", pid, WEXITSTATUS(status));
// Check to see if the PID is in the USAP pool and remove it if it is. if (RemoveUsapTableEntry(pid)) { ++usaps_removed; } } elseif (WIFSIGNALED(status)) { async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, "Process %d exited due to signal %d (%s)%s", pid, WTERMSIG(status), strsignal(WTERMSIG(status)), WCOREDUMP(status) ? "; core dumped" : "");
// If the process exited due to a signal other than SIGTERM, check to see // if the PID is in the USAP pool and remove it if it is. If the process // was closed by the Zygote using SIGTERM then the USAP pool entry will // have already been removed (see nativeEmptyUsapPool()). if (WTERMSIG(status) != SIGTERM && RemoveUsapTableEntry(pid)) { ++usaps_removed; } }
// If the just-crashed process is the system_server, bring down zygote // so that it is restarted by init and system server will be restarted // from there. if (pid == gSystemServerPid) { async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Exit zygote because system server (pid %d) has terminated", pid); kill(getpid(), SIGKILL); } }
// Note that we shouldn't consider ECHILD an error because // the secondary zygote might have no children left to wait for. if (pid < 0 && errno != ECHILD) { async_safe_format_log(ANDROID_LOG_WARN, LOG_TAG, "Zygote SIGCHLD error in waitpid: %s", strerror(errno)); }
if (usaps_removed > 0) { if (TEMP_FAILURE_RETRY(write(gUsapPoolEventFD, &usaps_removed, sizeof(usaps_removed))) == -1) { // If this write fails something went terribly wrong. We will now kill // the zygote and let the system bring it back up. async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, "Zygote failed to write to USAP pool event FD: %s", strerror(errno)); kill(getpid(), SIGKILL); } }
errno = saved_errno; } // line 495
// Configures the SIGCHLD/SIGHUP handlers for the zygote process. This is // configured very late, because earlier in the runtime we may fork() and // exec() other processes, and we want to waitpid() for those rather than // have them be harvested immediately. // // Ignore SIGHUP because all processes forked by the zygote are in the same // process group as the zygote and we don't want to be notified if we become // an orphaned group and have one or more stopped processes. This is not a // theoretical concern : // - we can become an orphaned group if one of our direct descendants forks // and is subsequently killed before its children. // - crash_dump routinely STOPs the process it's tracing. // // See issues b/71965619 and b/25567761 for further details. // // This ends up being called repeatedly before each fork(), but there's // no real harm in that. staticvoidSetSignalHandlers() { structsigactionsig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler};
graph TB
init[Initial process] --> fork[Fork]
fork -.Returns a new PID.-> original[Original Process Continues]
fork -.Returns zero .-> new[New Process]
在POSIX标准中(可移植操作系统接口Portable Operating System Interface of UNIX),fork的行为是这样的:复制整个用户空间的数据(通常使用copy-on-write的策略,所以可以实现的速度很快)以及所有系统对象,然后仅复制当前线程到子进程。这里:所有父进程中别的线程,到了子进程中都是突然蒸发掉的。对于锁来说,从OS看,每一个锁都有一个所有着,即最后一次lock它的线程。假设这么一个环境,在fork之前,有一个子线程lock了某个锁,获得了锁的所有权。fork以后,在子进程中,所有的额外线程都人间蒸发了。而锁却被正常复制了,在子进程看来,这个锁没有主任,所有没有任何人可以对它解锁。当子进程想lock这个锁时,不再有任何手段可以解开了。程序发生死锁