Merge "Initial "janitors" owner group."
diff --git a/adb/client/adb_install.cpp b/adb/client/adb_install.cpp
index 054cbac..bd5508c 100644
--- a/adb/client/adb_install.cpp
+++ b/adb/client/adb_install.cpp
@@ -501,6 +501,197 @@
return EXIT_FAILURE;
}
+int install_multi_package(int argc, const char** argv) {
+ // Find all APK arguments starting at end.
+ // All other arguments passed through verbatim.
+ int first_apk = -1;
+ for (int i = argc - 1; i >= 0; i--) {
+ const char* file = argv[i];
+ if (android::base::EndsWithIgnoreCase(file, ".apk")) {
+ first_apk = i;
+ } else {
+ break;
+ }
+ }
+
+ if (first_apk == -1) error_exit("need APK file on command line");
+
+ if (use_legacy_install()) {
+ fprintf(stderr, "adb: multi-package install is not supported on this device\n");
+ return EXIT_FAILURE;
+ }
+ std::string install_cmd = "exec:cmd package";
+
+ std::string multi_package_cmd =
+ android::base::StringPrintf("%s install-create --multi-package", install_cmd.c_str());
+
+ // Create multi-package install session
+ std::string error;
+ int fd = adb_connect(multi_package_cmd, &error);
+ if (fd < 0) {
+ fprintf(stderr, "adb: connect error for create multi-package: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
+ char buf[BUFSIZ];
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ int parent_session_id = -1;
+ if (!strncmp("Success", buf, 7)) {
+ char* start = strrchr(buf, '[');
+ char* end = strrchr(buf, ']');
+ if (start && end) {
+ *end = '\0';
+ parent_session_id = strtol(start + 1, nullptr, 10);
+ }
+ }
+ if (parent_session_id < 0) {
+ fprintf(stderr, "adb: failed to create multi-package session\n");
+ fputs(buf, stderr);
+ return EXIT_FAILURE;
+ }
+
+ fprintf(stdout, "Created parent session ID %d.\n", parent_session_id);
+
+ std::vector<int> session_ids;
+
+ // Valid session, now create the individual sessions and stream the APKs
+ int success = EXIT_FAILURE;
+ std::string individual_cmd =
+ android::base::StringPrintf("%s install-create", install_cmd.c_str());
+ std::string all_session_ids = "";
+ for (int i = 1; i < first_apk; i++) {
+ individual_cmd += " " + escape_arg(argv[i]);
+ }
+ std::string cmd = "";
+ for (int i = first_apk; i < argc; i++) {
+ // Create individual install session
+ fd = adb_connect(individual_cmd, &error);
+ if (fd < 0) {
+ fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
+ goto finalize_multi_package_session;
+ }
+ char buf[BUFSIZ];
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ int session_id = -1;
+ if (!strncmp("Success", buf, 7)) {
+ char* start = strrchr(buf, '[');
+ char* end = strrchr(buf, ']');
+ if (start && end) {
+ *end = '\0';
+ session_id = strtol(start + 1, nullptr, 10);
+ }
+ }
+ if (session_id < 0) {
+ fprintf(stderr, "adb: failed to create multi-package session\n");
+ fputs(buf, stderr);
+ goto finalize_multi_package_session;
+ }
+
+ fprintf(stdout, "Created child session ID %d.\n", session_id);
+ session_ids.push_back(session_id);
+
+ const char* file = argv[i];
+ struct stat sb;
+ if (stat(file, &sb) == -1) {
+ fprintf(stderr, "adb: failed to stat %s: %s\n", file, strerror(errno));
+ goto finalize_multi_package_session;
+ }
+
+ std::string cmd =
+ android::base::StringPrintf("%s install-write -S %" PRIu64 " %d %d_%s -",
+ install_cmd.c_str(), static_cast<uint64_t>(sb.st_size),
+ session_id, i, android::base::Basename(file).c_str());
+
+ int localFd = adb_open(file, O_RDONLY);
+ if (localFd < 0) {
+ fprintf(stderr, "adb: failed to open %s: %s\n", file, strerror(errno));
+ goto finalize_multi_package_session;
+ }
+
+ std::string error;
+ int remoteFd = adb_connect(cmd, &error);
+ if (remoteFd < 0) {
+ fprintf(stderr, "adb: connect error for write: %s\n", error.c_str());
+ adb_close(localFd);
+ goto finalize_multi_package_session;
+ }
+
+ copy_to_file(localFd, remoteFd);
+ read_status_line(remoteFd, buf, sizeof(buf));
+
+ adb_close(localFd);
+ adb_close(remoteFd);
+
+ if (strncmp("Success", buf, 7)) {
+ fprintf(stderr, "adb: failed to write %s\n", file);
+ fputs(buf, stderr);
+ goto finalize_multi_package_session;
+ }
+
+ all_session_ids += android::base::StringPrintf(" %d", session_id);
+ }
+
+ cmd = android::base::StringPrintf("%s install-add-session %d%s", install_cmd.c_str(),
+ parent_session_id, all_session_ids.c_str());
+ fd = adb_connect(cmd, &error);
+ if (fd < 0) {
+ fprintf(stderr, "adb: connect error for create: %s\n", error.c_str());
+ goto finalize_multi_package_session;
+ }
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ if (strncmp("Success", buf, 7)) {
+ fprintf(stderr, "adb: failed to link sessions (%s)\n", cmd.c_str());
+ fputs(buf, stderr);
+ goto finalize_multi_package_session;
+ }
+
+ // no failures means we can proceed with the assumption of success
+ success = 0;
+
+finalize_multi_package_session:
+ // Commit session if we streamed everything okay; otherwise abandon
+ std::string service =
+ android::base::StringPrintf("%s install-%s %d", install_cmd.c_str(),
+ success == 0 ? "commit" : "abandon", parent_session_id);
+ fd = adb_connect(service, &error);
+ if (fd < 0) {
+ fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
+ return EXIT_FAILURE;
+ }
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+
+ if (!strncmp("Success", buf, 7)) {
+ fputs(buf, stdout);
+ if (success == 0) {
+ return 0;
+ }
+ } else {
+ fprintf(stderr, "adb: failed to finalize session\n");
+ fputs(buf, stderr);
+ }
+
+ // try to abandon all remaining sessions
+ for (std::size_t i = 0; i < session_ids.size(); i++) {
+ service = android::base::StringPrintf("%s install-abandon %d", install_cmd.c_str(),
+ session_ids[i]);
+ fprintf(stderr, "Attempting to abandon session ID %d\n", session_ids[i]);
+ fd = adb_connect(service, &error);
+ if (fd < 0) {
+ fprintf(stderr, "adb: connect error for finalize: %s\n", error.c_str());
+ continue;
+ }
+ read_status_line(fd, buf, sizeof(buf));
+ adb_close(fd);
+ }
+ return EXIT_FAILURE;
+}
+
int delete_device_file(const std::string& filename) {
std::string cmd = "rm -f " + escape_arg(filename);
return send_shell_command(cmd);
diff --git a/adb/client/adb_install.h b/adb/client/adb_install.h
index 5b6c4cb..9946604 100644
--- a/adb/client/adb_install.h
+++ b/adb/client/adb_install.h
@@ -20,6 +20,7 @@
int install_app(int argc, const char** argv);
int install_multiple_app(int argc, const char** argv);
+int install_multi_package(int argc, const char** argv);
int uninstall_app(int argc, const char** argv);
int delete_device_file(const std::string& filename);
diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp
index 20fd036..9bc42e1 100644
--- a/adb/client/commandline.cpp
+++ b/adb/client/commandline.cpp
@@ -142,10 +142,13 @@
" -x: disable remote exit codes and stdout/stderr separation\n"
" emu COMMAND run emulator console command\n"
"\n"
- "app installation:\n"
+ "app installation (see also `adb shell cmd package help`):\n"
" install [-lrtsdg] [--instant] PACKAGE\n"
+ " push a single package to the device and install it\n"
" install-multiple [-lrtsdpg] [--instant] PACKAGE...\n"
- " push package(s) to the device and install them\n"
+ " push multiple APKs to the device for a single package and install them\n"
+ " install-multi-package [-lrtsdpg] [--instant] PACKAGE...\n"
+ " push one or more packages to the device and install them atomically\n"
" -r: replace existing application\n"
" -t: allow test packages\n"
" -d: allow version code downgrade (debuggable packages only)\n"
@@ -1734,6 +1737,9 @@
} else if (!strcmp(argv[0], "install-multiple")) {
if (argc < 2) error_exit("install-multiple requires an argument");
return install_multiple_app(argc, argv);
+ } else if (!strcmp(argv[0], "install-multi-package")) {
+ if (argc < 3) error_exit("install-multi-package requires an argument");
+ return install_multi_package(argc, argv);
} else if (!strcmp(argv[0], "uninstall")) {
if (argc < 2) error_exit("uninstall requires an argument");
return uninstall_app(argc, argv);
diff --git a/libnativebridge/Android.bp b/libnativebridge/Android.bp
index 92fd2a2..59cd033 100644
--- a/libnativebridge/Android.bp
+++ b/libnativebridge/Android.bp
@@ -17,6 +17,11 @@
"liblog",
],
+ stubs: {
+ symbol_file: "libnativebridge.map.txt",
+ versions: ["1"],
+ },
+
export_include_dirs: ["include"],
cflags: [
diff --git a/libnativebridge/include/nativebridge/native_bridge.h b/libnativebridge/include/nativebridge/native_bridge.h
index 28f1927..5aea967 100644
--- a/libnativebridge/include/nativebridge/native_bridge.h
+++ b/libnativebridge/include/nativebridge/native_bridge.h
@@ -17,12 +17,17 @@
#ifndef NATIVE_BRIDGE_H_
#define NATIVE_BRIDGE_H_
-#include "jni.h"
#include <signal.h>
+#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
+#include "jni.h"
+
+#ifdef __cplusplus
namespace android {
+extern "C" {
+#endif // __cplusplus
struct NativeBridgeRuntimeCallbacks;
struct NativeBridgeRuntimeValues;
@@ -32,11 +37,10 @@
// to the chain.
typedef bool (*NativeBridgeSignalHandlerFn)(int, siginfo_t*, void*);
-
// Open the native bridge, if any. Should be called by Runtime::Init(). A null library filename
// signals that we do not want to load a native bridge.
bool LoadNativeBridge(const char* native_bridge_library_filename,
- const NativeBridgeRuntimeCallbacks* runtime_callbacks);
+ const struct NativeBridgeRuntimeCallbacks* runtime_callbacks);
// Quick check whether a native bridge will be needed. This is based off of the instruction set
// of the process.
@@ -138,19 +142,17 @@
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
-native_bridge_namespace_t* NativeBridgeCreateNamespace(const char* name,
- const char* ld_library_path,
- const char* default_library_path,
- uint64_t type,
- const char* permitted_when_isolated_path,
- native_bridge_namespace_t* parent_ns);
+struct native_bridge_namespace_t* NativeBridgeCreateNamespace(
+ const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type,
+ const char* permitted_when_isolated_path, struct native_bridge_namespace_t* parent_ns);
// Creates a link which shares some libraries from one namespace to another.
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
-bool NativeBridgeLinkNamespaces(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
+bool NativeBridgeLinkNamespaces(struct native_bridge_namespace_t* from,
+ struct native_bridge_namespace_t* to,
const char* shared_libs_sonames);
// Load a shared library with namespace key that is supported by the native bridge.
@@ -159,10 +161,11 @@
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use NativeBridgeLoadLibrary() instead in non-namespace scenario.
-void* NativeBridgeLoadLibraryExt(const char* libpath, int flag, native_bridge_namespace_t* ns);
+void* NativeBridgeLoadLibraryExt(const char* libpath, int flag,
+ struct native_bridge_namespace_t* ns);
// Returns vendor namespace if it is enabled for the device and null otherwise
-native_bridge_namespace_t* NativeBridgeGetVendorNamespace();
+struct native_bridge_namespace_t* NativeBridgeGetVendorNamespace();
// Native bridge interfaces to runtime.
struct NativeBridgeCallbacks {
@@ -177,8 +180,8 @@
// runtime_cbs [IN] the pointer to NativeBridgeRuntimeCallbacks.
// Returns:
// true if initialization was successful.
- bool (*initialize)(const NativeBridgeRuntimeCallbacks* runtime_cbs, const char* private_dir,
- const char* instruction_set);
+ bool (*initialize)(const struct NativeBridgeRuntimeCallbacks* runtime_cbs,
+ const char* private_dir, const char* instruction_set);
// Load a shared library that is supported by the native bridge.
//
@@ -314,12 +317,12 @@
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
- native_bridge_namespace_t* (*createNamespace)(const char* name,
- const char* ld_library_path,
- const char* default_library_path,
- uint64_t type,
- const char* permitted_when_isolated_path,
- native_bridge_namespace_t* parent_ns);
+ struct native_bridge_namespace_t* (*createNamespace)(const char* name,
+ const char* ld_library_path,
+ const char* default_library_path,
+ uint64_t type,
+ const char* permitted_when_isolated_path,
+ struct native_bridge_namespace_t* parent_ns);
// Creates a link which shares some libraries from one namespace to another.
// NativeBridge's peer of android_link_namespaces() of dynamic linker.
@@ -334,8 +337,8 @@
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Should not use in non-namespace scenario.
- bool (*linkNamespaces)(native_bridge_namespace_t* from, native_bridge_namespace_t* to,
- const char* shared_libs_sonames);
+ bool (*linkNamespaces)(struct native_bridge_namespace_t* from,
+ struct native_bridge_namespace_t* to, const char* shared_libs_sonames);
// Load a shared library within a namespace.
// NativeBridge's peer of android_dlopen_ext() of dynamic linker, only supports namespace
@@ -350,7 +353,7 @@
//
// Starting with v3, NativeBridge has two scenarios: with/without namespace.
// Use loadLibrary instead in non-namespace scenario.
- void* (*loadLibraryExt)(const char* libpath, int flag, native_bridge_namespace_t* ns);
+ void* (*loadLibraryExt)(const char* libpath, int flag, struct native_bridge_namespace_t* ns);
// Get native bridge version of vendor namespace.
// The vendor namespace is the namespace used to load vendor public libraries.
@@ -359,7 +362,7 @@
//
// Returns:
// vendor namespace or null if it was not set up for the device
- native_bridge_namespace_t* (*getVendorNamespace)();
+ struct native_bridge_namespace_t* (*getVendorNamespace)();
};
// Runtime interfaces to native bridge.
@@ -396,6 +399,9 @@
uint32_t method_count);
};
-}; // namespace android
+#ifdef __cplusplus
+} // extern "C"
+} // namespace android
+#endif // __cplusplus
#endif // NATIVE_BRIDGE_H_
diff --git a/libnativebridge/libnativebridge.map.txt b/libnativebridge/libnativebridge.map.txt
new file mode 100644
index 0000000..a616b85
--- /dev/null
+++ b/libnativebridge/libnativebridge.map.txt
@@ -0,0 +1,45 @@
+#
+# Copyright (C) 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# TODO(b/122710865): Most of these uses come from libnativeloader, which should be bundled
+# together with libnativebridge in the APEX. Once this happens, prune this list.
+LIBNATIVEBRIDGE_1 {
+ global:
+ NativeBridgeIsSupported;
+ NativeBridgeLoadLibrary;
+ NativeBridgeUnloadLibrary;
+ NativeBridgeGetError;
+ NativeBridgeIsPathSupported;
+ NativeBridgeCreateNamespace;
+ NativeBridgeGetVendorNamespace;
+ NativeBridgeLinkNamespaces;
+ NativeBridgeLoadLibraryExt;
+ NativeBridgeInitAnonymousNamespace;
+ NativeBridgeInitialized;
+ NativeBridgeGetTrampoline;
+ LoadNativeBridge;
+ PreInitializeNativeBridge;
+ InitializeNativeBridge;
+ NativeBridgeGetVersion;
+ NativeBridgeGetSignalHandler;
+ UnloadNativeBridge;
+ NativeBridgeAvailable;
+ NeedsNativeBridge;
+ NativeBridgeError;
+ NativeBridgeNameAcceptable;
+ local:
+ *;
+};
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc
index e24307a..a2d8d81 100644
--- a/libnativebridge/native_bridge.cc
+++ b/libnativebridge/native_bridge.cc
@@ -33,6 +33,13 @@
namespace android {
+#ifdef __APPLE__
+template <typename T>
+void UNUSED(const T&) {}
+#endif
+
+extern "C" {
+
// Environment values required by the apps running with native bridge.
struct NativeBridgeRuntimeValues {
const char* os_arch;
@@ -252,10 +259,6 @@
return strncmp(instruction_set, ABI_STRING, strlen(ABI_STRING) + 1) != 0;
}
-#ifdef __APPLE__
-template<typename T> void UNUSED(const T&) {}
-#endif
-
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.");
@@ -626,4 +629,6 @@
return nullptr;
}
-}; // namespace android
+} // extern "C"
+
+} // namespace android
diff --git a/libnativebridge/tests/Android.bp b/libnativebridge/tests/Android.bp
index 222bc4c..744a4a8 100644
--- a/libnativebridge/tests/Android.bp
+++ b/libnativebridge/tests/Android.bp
@@ -86,3 +86,14 @@
],
header_libs: ["libbase_headers"],
}
+
+// Build the test for the C API.
+cc_test {
+ name: "libnativebridge-api-tests",
+ host_supported: true,
+ test_per_src: true,
+ srcs: [
+ "NativeBridgeApi.c",
+ ],
+ header_libs: ["libnativebridge-dummy-headers"],
+}
diff --git a/libnativebridge/tests/NativeBridgeApi.c b/libnativebridge/tests/NativeBridgeApi.c
new file mode 100644
index 0000000..7ab71fe
--- /dev/null
+++ b/libnativebridge/tests/NativeBridgeApi.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* The main purpose of this test is to ensure this C header compiles in C, so
+ * that no C++ features inadvertently leak into the C ABI. */
+#include "nativebridge/native_bridge.h"
+
+int main(int argc, char** argv) {
+ (void)argc;
+ (void)argv;
+ return 0;
+}
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index 89d4fc0..e267f58 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -221,7 +221,6 @@
"liblog",
"liblzma",
"libunwindstack",
- "libdexfile",
"libdexfile_support",
],
diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp
index 21ca47b..0149a42 100644
--- a/libunwindstack/tests/DexFileTest.cpp
+++ b/libunwindstack/tests/DexFileTest.cpp
@@ -21,7 +21,6 @@
#include <unordered_map>
#include <android-base/file.h>
-#include <dex/dex_file.h>
#include <gtest/gtest.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Memory.h>
@@ -40,17 +39,15 @@
TemporaryFile tf;
ASSERT_TRUE(tf.fd != -1);
- ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
- static_cast<size_t>(
- TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
+ ASSERT_EQ(size_t{10}, static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, 10))));
// Header too small.
EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
// Header correct, file too small.
ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
- ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write(
- tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+ ASSERT_EQ(sizeof(kDexData) - 1,
+ static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 1))));
EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr);
}
@@ -78,7 +75,7 @@
TEST(DexFileTest, from_memory_fail_too_small_for_header) {
MemoryFake memory;
- memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1);
+ memory.SetMemory(0x1000, kDexData, 10);
EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr);
}
@@ -187,15 +184,6 @@
ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset));
EXPECT_EQ("Main.main", method);
EXPECT_EQ(0U, method_offset);
-
- // Make sure that any data that is cached is still retrievable.
- ASSERT_TRUE(dex_file->GetMethodInformation(0x104, &method, &method_offset));
- EXPECT_EQ("Main.<init>", method);
- EXPECT_EQ(4U, method_offset);
-
- ASSERT_TRUE(dex_file->GetMethodInformation(0x119, &method, &method_offset));
- EXPECT_EQ("Main.main", method);
- EXPECT_EQ(1U, method_offset);
}
TEST(DexFileTest, get_method_empty) {
@@ -210,12 +198,6 @@
EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset));
EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
-
- // Make sure that once the whole dex file has been cached, no problems occur.
- EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset));
-
- // Choose a value that is in the cached map, but not in a valid method.
- EXPECT_FALSE(dex_file->GetMethodInformation(0x110, &method, &method_offset));
}
} // namespace unwindstack