Loading include/nativebridge/native_bridge.h +1 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ bool NeedsNativeBridge(const char* instruction_set); // Do the early initialization part of the native bridge, if necessary. This should be done under // high privileges. void PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); // Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv* // will be used to modify the app environment for the bridge. Loading libnativebridge/Android.mk +3 −3 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS := -Werror -Wall LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both Loading @@ -30,7 +30,7 @@ LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS := -Werror -Wall LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both Loading libnativebridge/native_bridge.cc +92 −39 Original line number Diff line number Diff line Loading @@ -43,14 +43,16 @@ static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf"; enum class NativeBridgeState { kNotSetup, // Initial state. kOpened, // After successful dlopen. kPreInitialized, // After successful pre-initialization. kInitialized, // After successful initialization. kClosed // Closed or errors. }; static const char* kNotSetupString = "kNotSetup"; static const char* kOpenedString = "kOpened"; static const char* kInitializedString = "kInitialized"; static const char* kClosedString = "kClosed"; static constexpr const char* kNotSetupString = "kNotSetup"; static constexpr const char* kOpenedString = "kOpened"; static constexpr const char* kPreInitializedString = "kPreInitialized"; static constexpr const char* kInitializedString = "kInitialized"; static constexpr const char* kClosedString = "kClosed"; static const char* GetNativeBridgeStateString(NativeBridgeState state) { switch (state) { Loading @@ -60,6 +62,9 @@ static const char* GetNativeBridgeStateString(NativeBridgeState state) { case NativeBridgeState::kOpened: return kOpenedString; case NativeBridgeState::kPreInitialized: return kPreInitializedString; case NativeBridgeState::kInitialized: return kInitializedString; Loading @@ -82,8 +87,14 @@ static NativeBridgeCallbacks* callbacks = nullptr; // Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge. static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr; // The app's data directory. static char* app_data_dir = nullptr; // The app's code cache directory. static char* app_code_cache_dir = nullptr; // Code cache directory (relative to the application private directory) // Ideally we'd like to call into framework to retrieve this name. However that's considered an // implementation detail and will require either hacks or consistent refactorings. We compromise // and hard code the directory name again here. static constexpr const char* kCodeCacheDir = "code_cache"; static constexpr uint32_t kNativeBridgeCallbackVersion = 1; Loading Loading @@ -132,6 +143,13 @@ static bool VersionCheck(NativeBridgeCallbacks* cb) { return cb != nullptr && cb->version == kNativeBridgeCallbackVersion; } static void CloseNativeBridge(bool with_error) { state = NativeBridgeState::kClosed; had_error |= with_error; delete[] app_code_cache_dir; app_code_cache_dir = nullptr; } bool LoadNativeBridge(const char* nb_library_filename, const NativeBridgeRuntimeCallbacks* runtime_cbs) { // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not Loading @@ -149,12 +167,11 @@ bool LoadNativeBridge(const char* nb_library_filename, } if (nb_library_filename == nullptr || *nb_library_filename == 0) { state = NativeBridgeState::kClosed; return true; CloseNativeBridge(false); return false; } else { if (!NativeBridgeNameAcceptable(nb_library_filename)) { state = NativeBridgeState::kClosed; had_error = true; CloseNativeBridge(true); } else { // Try to open the library. void* handle = dlopen(nb_library_filename, RTLD_LAZY); Loading @@ -178,8 +195,7 @@ bool LoadNativeBridge(const char* nb_library_filename, // Two failure conditions: could not find library (dlopen failed), or could not find native // bridge interface (dlsym failed). Both are an error and close the native bridge. if (callbacks == nullptr) { had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } else { runtime_callbacks = runtime_cbs; state = NativeBridgeState::kOpened; Loading Loading @@ -216,19 +232,32 @@ bool NeedsNativeBridge(const char* instruction_set) { template<typename T> void UNUSED(const T&) {} #endif void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { if (state != NativeBridgeState::kOpened) { ALOGE("Invalid state: native bridge is expected to be opened."); CloseNativeBridge(true); return false; } if (app_data_dir_in == nullptr) { return; ALOGE("Application private directory cannot be null."); CloseNativeBridge(true); return false; } const size_t len = strlen(app_data_dir_in); // Make a copy for us. app_data_dir = new char[len]; strncpy(app_data_dir, app_data_dir_in, len); // 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; #ifndef __APPLE__ if (instruction_set == nullptr) { return; return true; } size_t isa_len = strlen(instruction_set); if (isa_len > 10) { Loading @@ -237,11 +266,11 @@ void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct // be another instruction set in the future. ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.", instruction_set); return; return true; } // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. If the file does not exist, the // mount command will fail, so we safe the extra file existence check... // If the file does not exist, the mount command will fail, // so we save the extra file existence check. char cpuinfo_path[1024]; #ifdef HAVE_ANDROID_OS Loading @@ -263,10 +292,12 @@ void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct nullptr)) == -1) { // "Data." ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno)); } #else #else // __APPLE__ UNUSED(instruction_set); ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible."); #endif return true; } static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) { Loading Loading @@ -353,20 +384,40 @@ bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) { // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that // point we are not multi-threaded, so we do not need locking here. if (state == NativeBridgeState::kOpened) { // Try to initialize. if (callbacks->initialize(runtime_callbacks, app_data_dir, instruction_set)) { 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) { ALOGE("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); CloseNativeBridge(true); } } else { ALOGE("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); CloseNativeBridge(true); } } else if (!S_ISDIR(st.st_mode)) { ALOGE("Code cache is not a directory %s.", app_code_cache_dir); CloseNativeBridge(true); } // If we're still PreInitialized (dind'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); state = NativeBridgeState::kInitialized; // We no longer need the code cache path, release the memory. delete[] app_code_cache_dir; app_code_cache_dir = nullptr; } else { // Unload the library. dlclose(native_bridge_handle); had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } } } else { had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } return state == NativeBridgeState::kInitialized; Loading @@ -378,22 +429,22 @@ void UnloadNativeBridge() { switch(state) { case NativeBridgeState::kOpened: case NativeBridgeState::kPreInitialized: case NativeBridgeState::kInitialized: // Unload. dlclose(native_bridge_handle); CloseNativeBridge(false); break; case NativeBridgeState::kNotSetup: // Not even set up. Error. had_error = true; CloseNativeBridge(true); break; case NativeBridgeState::kClosed: // Ignore. break; } state = NativeBridgeState::kClosed; } bool NativeBridgeError() { Loading @@ -401,7 +452,9 @@ bool NativeBridgeError() { } bool NativeBridgeAvailable() { return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized; return state == NativeBridgeState::kOpened || state == NativeBridgeState::kPreInitialized || state == NativeBridgeState::kInitialized; } bool NativeBridgeInitialized() { Loading libnativebridge/tests/Android.mk +10 −2 Original line number Diff line number Diff line # Build the unit tests. LOCAL_PATH := $(call my-dir) include $(LOCAL_PATH)/Android.nativebridge-dummy.mk include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ CompleteFlow_test.cpp \ InvalidCharsNativeBridge_test.cpp \ NeedsNativeBridge_test.cpp \ PreInitializeNativeBridge_test.cpp \ PreInitializeNativeBridgeFail1_test.cpp \ PreInitializeNativeBridgeFail2_test.cpp \ ReSetupNativeBridge_test.cpp \ UnavailableNativeBridge_test.cpp \ ValidNameNativeBridge_test.cpp shared_libraries := \ liblog \ libnativebridge libnativebridge \ libnativebridge-dummy $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ Loading libnativebridge/tests/Android.nativebridge-dummy.mk 0 → 100644 +34 −0 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) NATIVE_BRIDGE_COMMON_SRC_FILES := \ DummyNativeBridge.cpp # Shared library for target # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE:= libnativebridge-dummy LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_CLANG := true LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both include $(BUILD_SHARED_LIBRARY) # Shared library for host # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE:= libnativebridge-dummy LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_CLANG := true LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) Loading
include/nativebridge/native_bridge.h +1 −1 Original line number Diff line number Diff line Loading @@ -37,7 +37,7 @@ bool NeedsNativeBridge(const char* instruction_set); // Do the early initialization part of the native bridge, if necessary. This should be done under // high privileges. void PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); // Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv* // will be used to modify the app environment for the bridge. Loading
libnativebridge/Android.mk +3 −3 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS := -Werror -Wall LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both Loading @@ -30,7 +30,7 @@ LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc LOCAL_CFLAGS := -Werror -Wall LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both Loading
libnativebridge/native_bridge.cc +92 −39 Original line number Diff line number Diff line Loading @@ -43,14 +43,16 @@ static constexpr const char* kNativeBridgeInterfaceSymbol = "NativeBridgeItf"; enum class NativeBridgeState { kNotSetup, // Initial state. kOpened, // After successful dlopen. kPreInitialized, // After successful pre-initialization. kInitialized, // After successful initialization. kClosed // Closed or errors. }; static const char* kNotSetupString = "kNotSetup"; static const char* kOpenedString = "kOpened"; static const char* kInitializedString = "kInitialized"; static const char* kClosedString = "kClosed"; static constexpr const char* kNotSetupString = "kNotSetup"; static constexpr const char* kOpenedString = "kOpened"; static constexpr const char* kPreInitializedString = "kPreInitialized"; static constexpr const char* kInitializedString = "kInitialized"; static constexpr const char* kClosedString = "kClosed"; static const char* GetNativeBridgeStateString(NativeBridgeState state) { switch (state) { Loading @@ -60,6 +62,9 @@ static const char* GetNativeBridgeStateString(NativeBridgeState state) { case NativeBridgeState::kOpened: return kOpenedString; case NativeBridgeState::kPreInitialized: return kPreInitializedString; case NativeBridgeState::kInitialized: return kInitializedString; Loading @@ -82,8 +87,14 @@ static NativeBridgeCallbacks* callbacks = nullptr; // Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge. static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr; // The app's data directory. static char* app_data_dir = nullptr; // The app's code cache directory. static char* app_code_cache_dir = nullptr; // Code cache directory (relative to the application private directory) // Ideally we'd like to call into framework to retrieve this name. However that's considered an // implementation detail and will require either hacks or consistent refactorings. We compromise // and hard code the directory name again here. static constexpr const char* kCodeCacheDir = "code_cache"; static constexpr uint32_t kNativeBridgeCallbackVersion = 1; Loading Loading @@ -132,6 +143,13 @@ static bool VersionCheck(NativeBridgeCallbacks* cb) { return cb != nullptr && cb->version == kNativeBridgeCallbackVersion; } static void CloseNativeBridge(bool with_error) { state = NativeBridgeState::kClosed; had_error |= with_error; delete[] app_code_cache_dir; app_code_cache_dir = nullptr; } bool LoadNativeBridge(const char* nb_library_filename, const NativeBridgeRuntimeCallbacks* runtime_cbs) { // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not Loading @@ -149,12 +167,11 @@ bool LoadNativeBridge(const char* nb_library_filename, } if (nb_library_filename == nullptr || *nb_library_filename == 0) { state = NativeBridgeState::kClosed; return true; CloseNativeBridge(false); return false; } else { if (!NativeBridgeNameAcceptable(nb_library_filename)) { state = NativeBridgeState::kClosed; had_error = true; CloseNativeBridge(true); } else { // Try to open the library. void* handle = dlopen(nb_library_filename, RTLD_LAZY); Loading @@ -178,8 +195,7 @@ bool LoadNativeBridge(const char* nb_library_filename, // Two failure conditions: could not find library (dlopen failed), or could not find native // bridge interface (dlsym failed). Both are an error and close the native bridge. if (callbacks == nullptr) { had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } else { runtime_callbacks = runtime_cbs; state = NativeBridgeState::kOpened; Loading Loading @@ -216,19 +232,32 @@ bool NeedsNativeBridge(const char* instruction_set) { template<typename T> void UNUSED(const T&) {} #endif void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { if (state != NativeBridgeState::kOpened) { ALOGE("Invalid state: native bridge is expected to be opened."); CloseNativeBridge(true); return false; } if (app_data_dir_in == nullptr) { return; ALOGE("Application private directory cannot be null."); CloseNativeBridge(true); return false; } const size_t len = strlen(app_data_dir_in); // Make a copy for us. app_data_dir = new char[len]; strncpy(app_data_dir, app_data_dir_in, len); // 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; #ifndef __APPLE__ if (instruction_set == nullptr) { return; return true; } size_t isa_len = strlen(instruction_set); if (isa_len > 10) { Loading @@ -237,11 +266,11 @@ void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct // be another instruction set in the future. ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.", instruction_set); return; return true; } // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. If the file does not exist, the // mount command will fail, so we safe the extra file existence check... // If the file does not exist, the mount command will fail, // so we save the extra file existence check. char cpuinfo_path[1024]; #ifdef HAVE_ANDROID_OS Loading @@ -263,10 +292,12 @@ void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruct nullptr)) == -1) { // "Data." ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno)); } #else #else // __APPLE__ UNUSED(instruction_set); ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible."); #endif return true; } static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) { Loading Loading @@ -353,20 +384,40 @@ bool InitializeNativeBridge(JNIEnv* env, const char* instruction_set) { // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that // point we are not multi-threaded, so we do not need locking here. if (state == NativeBridgeState::kOpened) { // Try to initialize. if (callbacks->initialize(runtime_callbacks, app_data_dir, instruction_set)) { 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) { ALOGE("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); CloseNativeBridge(true); } } else { ALOGE("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); CloseNativeBridge(true); } } else if (!S_ISDIR(st.st_mode)) { ALOGE("Code cache is not a directory %s.", app_code_cache_dir); CloseNativeBridge(true); } // If we're still PreInitialized (dind'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); state = NativeBridgeState::kInitialized; // We no longer need the code cache path, release the memory. delete[] app_code_cache_dir; app_code_cache_dir = nullptr; } else { // Unload the library. dlclose(native_bridge_handle); had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } } } else { had_error = true; state = NativeBridgeState::kClosed; CloseNativeBridge(true); } return state == NativeBridgeState::kInitialized; Loading @@ -378,22 +429,22 @@ void UnloadNativeBridge() { switch(state) { case NativeBridgeState::kOpened: case NativeBridgeState::kPreInitialized: case NativeBridgeState::kInitialized: // Unload. dlclose(native_bridge_handle); CloseNativeBridge(false); break; case NativeBridgeState::kNotSetup: // Not even set up. Error. had_error = true; CloseNativeBridge(true); break; case NativeBridgeState::kClosed: // Ignore. break; } state = NativeBridgeState::kClosed; } bool NativeBridgeError() { Loading @@ -401,7 +452,9 @@ bool NativeBridgeError() { } bool NativeBridgeAvailable() { return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized; return state == NativeBridgeState::kOpened || state == NativeBridgeState::kPreInitialized || state == NativeBridgeState::kInitialized; } bool NativeBridgeInitialized() { Loading
libnativebridge/tests/Android.mk +10 −2 Original line number Diff line number Diff line # Build the unit tests. LOCAL_PATH := $(call my-dir) include $(LOCAL_PATH)/Android.nativebridge-dummy.mk include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ CompleteFlow_test.cpp \ InvalidCharsNativeBridge_test.cpp \ NeedsNativeBridge_test.cpp \ PreInitializeNativeBridge_test.cpp \ PreInitializeNativeBridgeFail1_test.cpp \ PreInitializeNativeBridgeFail2_test.cpp \ ReSetupNativeBridge_test.cpp \ UnavailableNativeBridge_test.cpp \ ValidNameNativeBridge_test.cpp shared_libraries := \ liblog \ libnativebridge libnativebridge \ libnativebridge-dummy $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ Loading
libnativebridge/tests/Android.nativebridge-dummy.mk 0 → 100644 +34 −0 Original line number Diff line number Diff line LOCAL_PATH:= $(call my-dir) NATIVE_BRIDGE_COMMON_SRC_FILES := \ DummyNativeBridge.cpp # Shared library for target # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE:= libnativebridge-dummy LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_CLANG := true LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both include $(BUILD_SHARED_LIBRARY) # Shared library for host # ======================================================== include $(CLEAR_VARS) LOCAL_MODULE:= libnativebridge-dummy LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) LOCAL_CLANG := true LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY)