nativebridge: Support app-zygote

1. Allow initialization without app data directory, since isolated
processes don't have any external storage
2. Skip initialization if it was already called. This happens for
an app forked from an app-zygote

Test: CtsExternalServiceTestCases
android.externalservice.cts.ExternalServiceTest
testBindExternalServiceWithZygote
Test: CtsSeccompHostTestCases
android.seccomp.cts.SeccompHostJUnit4DeviceTest
testAppZygoteSyscalls
both for Q.sdk_gphone_x86_arm.armeabi-v7a
Bug: 143143718
Bug: 146904103

Change-Id: I08b51504ccba11dd0e5c03ca7ac728d38e7cde9c
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index 6790a18..1a54ace 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -268,18 +268,17 @@
     return false;
   }
 
-  if (app_data_dir_in == nullptr) {
-    ALOGE("Application private directory cannot be null.");
-    CloseNativeBridge(true);
-    return false;
+  if (app_data_dir_in != nullptr) {
+    // Create the path to the application code cache directory.
+    // The memory will be release after Initialization or when the native bridge is closed.
+    const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2;  // '\0' + '/'
+    app_code_cache_dir = new char[len];
+    snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
+  } else {
+    ALOGW("Application private directory isn't available.");
+    app_code_cache_dir = nullptr;
   }
 
-  // Create the path to the application code cache directory.
-  // The memory will be release after Initialization or when the native bridge is closed.
-  const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2;  // '\0' + '/'
-  app_code_cache_dir = new char[len];
-  snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir);
-
   // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo.
   // Failure is not fatal and will keep the native bridge in kPreInitialized.
   state = NativeBridgeState::kPreInitialized;
@@ -414,24 +413,28 @@
   // point we are not multi-threaded, so we do not need locking here.
 
   if (state == NativeBridgeState::kPreInitialized) {
-    // Check for code cache: if it doesn't exist try to create it.
-    struct stat st;
-    if (stat(app_code_cache_dir, &st) == -1) {
-      if (errno == ENOENT) {
-        if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
-          ALOGW("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+    if (app_code_cache_dir != nullptr) {
+      // Check for code cache: if it doesn't exist try to create it.
+      struct stat st;
+      if (stat(app_code_cache_dir, &st) == -1) {
+        if (errno == ENOENT) {
+          if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) {
+            ALOGW("Cannot create code cache directory %s: %s.",
+                  app_code_cache_dir, strerror(errno));
+            ReleaseAppCodeCacheDir();
+          }
+        } else {
+          ALOGW("Cannot stat code cache directory %s: %s.",
+                app_code_cache_dir, strerror(errno));
           ReleaseAppCodeCacheDir();
         }
-      } else {
-        ALOGW("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno));
+      } else if (!S_ISDIR(st.st_mode)) {
+        ALOGW("Code cache is not a directory %s.", app_code_cache_dir);
         ReleaseAppCodeCacheDir();
       }
-    } else if (!S_ISDIR(st.st_mode)) {
-      ALOGW("Code cache is not a directory %s.", app_code_cache_dir);
-      ReleaseAppCodeCacheDir();
     }
 
-    // If we're still PreInitialized (dind't fail the code cache checks) try to initialize.
+    // If we're still PreInitialized (didn't fail the code cache checks) try to initialize.
     if (state == NativeBridgeState::kPreInitialized) {
       if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) {
         SetupEnvironment(callbacks, env, instruction_set);
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index def48e8..9287536 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -111,6 +111,11 @@
 }
 
 void InitializeNativeBridge(JNIEnv* env, const char* instruction_set) {
+  if (android::NativeBridgeInitialized()) {
+    // This happens in apps forked from app-zygote, since native bridge
+    // is initialized in the zygote.
+    return;
+  }
   if (android::InitializeNativeBridge(env, instruction_set)) {
     if (android::NativeBridgeGetVersion() >= 2U) {
 #ifdef _NSIG  // Undefined on Apple, but we don't support running on Mac, anyways.