Merge "healthd: Don't take device-scoped battery as the main system battery."
diff --git a/TEST_MAPPING b/TEST_MAPPING
index e3a8675..44c47f3 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,6 +28,9 @@
"name": "fs_mgr_vendor_overlay_test"
},
{
+ "name": "init_kill_services_test"
+ },
+ {
"name": "libbase_test"
},
{
diff --git a/adb/Android.bp b/adb/Android.bp
index 1b7a266..d8fa713 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -387,17 +387,17 @@
generated_headers: ["platform_tools_version"],
static_libs: [
- "libadbconnection_server",
- "libapp_processes_protos_lite",
"libdiagnose_usb",
],
shared_libs: [
+ "libadbconnection_server",
"libadb_crypto",
"libadb_pairing_connection",
"libadb_protos",
"libadb_tls_connection",
"libadbd_auth",
+ "libapp_processes_protos_lite",
"libasyncio",
"libbase",
"libcrypto",
@@ -432,6 +432,7 @@
exclude_shared_libs: [
"libadb_pairing_auth",
"libadb_pairing_connection",
+ "libapp_processes_protos_lite",
],
}
},
@@ -458,9 +459,7 @@
static_libs: [
"libadbconnection_server",
"libadbd_core",
- "libapp_processes_protos_lite",
"libdiagnose_usb",
- "libprotobuf-cpp-lite",
],
shared_libs: [
@@ -470,12 +469,14 @@
"libadb_tls_connection",
"libadbd_auth",
"libadbd_fs",
+ "libapp_processes_protos_lite",
"libasyncio",
"libbase",
"libcrypto",
"libcrypto_utils",
"libcutils_sockets",
"liblog",
+ "libprotobuf-cpp-lite",
],
target: {
@@ -514,15 +515,14 @@
// libminadbd wants both, as it's used to build native tests.
compile_multilib: "both",
- // libadbd doesn't build any additional source, but to expose libadbd_core as a shared library.
whole_static_libs: [
- "libadbconnection_server",
"libadbd_core",
- "libapp_processes_protos_lite",
- "libprotobuf-cpp-lite",
],
shared_libs: [
+ "libadbconnection_server",
+ "libapp_processes_protos_lite",
+ "libprotobuf-cpp-lite",
"libadb_crypto",
"libadb_pairing_connection",
"libadb_tls_connection",
diff --git a/adb/daemon/jdwp_service.cpp b/adb/daemon/jdwp_service.cpp
index c99aead..adae9f7 100644
--- a/adb/daemon/jdwp_service.cpp
+++ b/adb/daemon/jdwp_service.cpp
@@ -16,6 +16,7 @@
#if !ADB_HOST
+#if !defined(__ANDROID_RECOVERY__)
#define TRACE_TAG JDWP
#include "sysdeps.h"
@@ -459,7 +460,7 @@
return -1;
}
-asocket* create_process_tracker_service_socket(TrackerKind kind) {
+static asocket* create_process_tracker_service_socket(TrackerKind kind) {
auto t = std::make_unique<JdwpTracker>(kind, true);
if (!t) {
LOG(FATAL) << "failed to allocate JdwpTracker";
@@ -509,4 +510,28 @@
return 0;
}
+#else // !defined(__ANDROID_RECOVERY)
+#include "adb.h"
+
+asocket* create_jdwp_service_socket(void) {
+ return nullptr;
+}
+
+unique_fd create_jdwp_connection_fd(int pid) {
+ return {};
+}
+
+asocket* create_app_tracker_service_socket() {
+ return nullptr;
+}
+
+asocket* create_jdwp_tracker_service_socket() {
+ return nullptr;
+}
+
+int init_jdwp() {
+ return 0;
+}
+
+#endif /* defined(__ANDROID_RECOVERY__) */
#endif /* !ADB_HOST */
diff --git a/base/Android.bp b/base/Android.bp
index 12de3b2..894ad6c 100644
--- a/base/Android.bp
+++ b/base/Android.bp
@@ -74,10 +74,6 @@
"test_utils.cpp",
],
- static: {
- cflags: ["-DNO_LIBLOG_DLSYM"],
- },
-
cppflags: ["-Wexit-time-destructors"],
shared_libs: ["liblog"],
target: {
diff --git a/base/liblog_symbols.cpp b/base/liblog_symbols.cpp
index 8d59179..ba4c161 100644
--- a/base/liblog_symbols.cpp
+++ b/base/liblog_symbols.cpp
@@ -16,11 +16,9 @@
#include "liblog_symbols.h"
-#if defined(__ANDROID__)
-#if !defined(NO_LIBLOG_DLSYM) || defined(__ANDROID_APEX__)
+#if defined(__ANDROID_SDK_VERSION__) && (__ANDROID_SDK_VERSION__ <= 29)
#define USE_DLSYM
#endif
-#endif
#ifdef USE_DLSYM
#include <dlfcn.h>
diff --git a/init/init.cpp b/init/init.cpp
index b29dfa3..4289dcf 100644
--- a/init/init.cpp
+++ b/init/init.cpp
@@ -713,8 +713,15 @@
InitKernelLogging(argv);
LOG(INFO) << "init second stage started!";
- // Will handle EPIPE at the time of write by checking the errno
- signal(SIGPIPE, SIG_IGN);
+ // Init should not crash because of a dependence on any other process, therefore we ignore
+ // SIGPIPE and handle EPIPE at the call site directly. Note that setting a signal to SIG_IGN
+ // is inherited across exec, but custom signal handlers are not. Since we do not want to
+ // ignore SIGPIPE for child processes, we set a no-op function for the signal handler instead.
+ {
+ struct sigaction action = {.sa_flags = SA_RESTART};
+ action.sa_handler = [](int) {};
+ sigaction(SIGPIPE, &action, nullptr);
+ }
// Set init and its forked children's oom_adj.
if (auto result =
diff --git a/init/selinux.cpp b/init/selinux.cpp
index acbcbd6..808cb7f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -539,9 +539,9 @@
// adb remount, snapshot-based updates, and DSUs all create files during
// first-stage init.
- selinux_android_restorecon("/metadata", SELINUX_ANDROID_RESTORECON_RECURSE);
-
selinux_android_restorecon(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0);
+ selinux_android_restorecon("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE |
+ SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
}
int SelinuxKlogCallback(int type, const char* fmt, ...) {
diff --git a/init/test_kill_services/Android.bp b/init/test_kill_services/Android.bp
new file mode 100644
index 0000000..f6e85e2
--- /dev/null
+++ b/init/test_kill_services/Android.bp
@@ -0,0 +1,7 @@
+cc_test {
+ name: "init_kill_services_test",
+ srcs: ["init_kill_services_test.cpp"],
+ shared_libs: ["libbase"],
+ test_suites: ["general-tests"],
+ require_root: true,
+}
diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp
new file mode 100644
index 0000000..7e543f2
--- /dev/null
+++ b/init/test_kill_services/init_kill_services_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <android-base/properties.h>
+
+#include <iostream>
+
+using ::android::base::GetProperty;
+using ::android::base::SetProperty;
+
+void ExpectKillingServiceRecovers(const std::string& service_name) {
+ const std::string status_prop = "init.svc." + service_name;
+ const std::string pid_prop = "init.svc_debug_pid." + service_name;
+
+ const std::string initial_pid = GetProperty(pid_prop, "");
+
+ EXPECT_EQ("running", GetProperty(status_prop, "")) << status_prop;
+ EXPECT_NE("", initial_pid) << pid_prop;
+
+ EXPECT_EQ(0, system(("kill -9 " + initial_pid).c_str()));
+
+ constexpr size_t kMaxWaitMilliseconds = 10000;
+ constexpr size_t kRetryWaitMilliseconds = 100;
+
+ constexpr size_t kRetryTimes = kMaxWaitMilliseconds / kRetryWaitMilliseconds;
+
+ for (size_t retry = 0; retry < kRetryTimes; retry++) {
+ const std::string& pid = GetProperty(pid_prop, "");
+ if (pid != initial_pid && pid != "") break;
+ usleep(kRetryWaitMilliseconds * 1000);
+ }
+
+ // svc_debug_pid is set after svc property
+ EXPECT_EQ("running", GetProperty(status_prop, ""));
+}
+
+class InitKillServicesTest : public ::testing::TestWithParam<std::string> {};
+
+TEST_P(InitKillServicesTest, KillCriticalProcesses) {
+ ExpectKillingServiceRecovers(GetParam());
+
+ // sanity check init is still responding
+ EXPECT_TRUE(SetProperty("test.death.test", "asdf"));
+ EXPECT_EQ(GetProperty("test.death.test", ""), "asdf");
+ EXPECT_TRUE(SetProperty("test.death.test", ""));
+}
+
+static inline std::string PrintName(const testing::TestParamInfo<std::string>& info) {
+ return info.param;
+}
+
+INSTANTIATE_TEST_CASE_P(DeathTest, InitKillServicesTest,
+ ::testing::Values("lmkd", "ueventd", "hwservicemanager", "servicemanager"),
+ PrintName);
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 1bbffaf..4081b21 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -60,6 +60,8 @@
srcs: [
"zip_archive.cc",
"zip_archive_stream_entry.cc",
+ "zip_cd_entry_map.cc",
+ "zip_error.cpp",
"zip_writer.cc",
],
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 047af90..098a9cb 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -126,6 +126,9 @@
int32_t OpenArchiveFd(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
bool assume_ownership = true);
+int32_t OpenArchiveFdRange(const int fd, const char* debugFileName, ZipArchiveHandle* handle,
+ off64_t length, off64_t offset, bool assume_ownership = true);
+
int32_t OpenArchiveFromMemory(const void* address, size_t length, const char* debugFileName,
ZipArchiveHandle* handle);
/*
@@ -222,6 +225,12 @@
int GetFileDescriptor(const ZipArchiveHandle archive);
+/**
+ * Returns the offset of the zip archive in the backing file descriptor, or 0 if the zip archive is
+ * not backed by a file descriptor.
+ */
+off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive);
+
const char* ErrorCodeString(int32_t error_code);
#if !defined(_WIN32)
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 4451507..aa8bafc 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -85,100 +85,6 @@
* of the string length into the hash table entry.
*/
-/*
- * Round up to the next highest power of 2.
- *
- * Found on http://graphics.stanford.edu/~seander/bithacks.html.
- */
-static uint32_t RoundUpPower2(uint32_t val) {
- val--;
- val |= val >> 1;
- val |= val >> 2;
- val |= val >> 4;
- val |= val >> 8;
- val |= val >> 16;
- val++;
-
- return val;
-}
-
-static uint32_t ComputeHash(std::string_view name) {
- return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
-}
-
-// Convert a ZipEntry to a hash table index, verifying that it's in a valid range.
-std::pair<int32_t, uint64_t> CdEntryMapZip32::GetCdEntryOffset(std::string_view name,
- const uint8_t* start) const {
- const uint32_t hash = ComputeHash(name);
-
- // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
- uint32_t ent = hash & (hash_table_size_ - 1);
- while (hash_table_[ent].name_offset != 0) {
- if (hash_table_[ent].ToStringView(start) == name) {
- return {0, hash_table_[ent].name_offset};
- }
- ent = (ent + 1) & (hash_table_size_ - 1);
- }
-
- ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
- return {kEntryNotFound, 0};
-}
-
-int32_t CdEntryMapZip32::AddToMap(std::string_view name, const uint8_t* start) {
- const uint64_t hash = ComputeHash(name);
- uint32_t ent = hash & (hash_table_size_ - 1);
-
- /*
- * We over-allocated the table, so we're guaranteed to find an empty slot.
- * Further, we guarantee that the hashtable size is not 0.
- */
- while (hash_table_[ent].name_offset != 0) {
- if (hash_table_[ent].ToStringView(start) == name) {
- // We've found a duplicate entry. We don't accept duplicates.
- ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
- return kDuplicateEntry;
- }
- ent = (ent + 1) & (hash_table_size_ - 1);
- }
-
- // `name` has already been validated before entry.
- const char* start_char = reinterpret_cast<const char*>(start);
- hash_table_[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
- hash_table_[ent].name_length = static_cast<uint16_t>(name.size());
- return 0;
-}
-
-void CdEntryMapZip32::ResetIteration() {
- current_position_ = 0;
-}
-
-std::pair<std::string_view, uint64_t> CdEntryMapZip32::Next(const uint8_t* cd_start) {
- while (current_position_ < hash_table_size_) {
- const auto& entry = hash_table_[current_position_];
- current_position_ += 1;
-
- if (entry.name_offset != 0) {
- return {entry.ToStringView(cd_start), entry.name_offset};
- }
- }
- // We have reached the end of the hash table.
- return {};
-}
-
-CdEntryMapZip32::CdEntryMapZip32(uint16_t num_entries) {
- hash_table_size_ = RoundUpPower2(1 + (num_entries * 4) / 3);
- hash_table_ = {
- reinterpret_cast<ZipStringOffset*>(calloc(hash_table_size_, sizeof(ZipStringOffset))), free};
-}
-
-std::unique_ptr<CdEntryMapInterface> CdEntryMapZip32::Create(uint16_t num_entries) {
- auto entry_map = new CdEntryMapZip32(num_entries);
- CHECK(entry_map->hash_table_ != nullptr)
- << "Zip: unable to allocate the " << entry_map->hash_table_size_
- << " entry hash_table, entry size: " << sizeof(ZipStringOffset);
- return std::unique_ptr<CdEntryMapInterface>(entry_map);
-}
-
#if defined(__BIONIC__)
uint64_t GetOwnerTag(const ZipArchive* archive) {
return android_fdsan_create_owner_tag(ANDROID_FDSAN_OWNER_TYPE_ZIPARCHIVE,
@@ -186,8 +92,8 @@
}
#endif
-ZipArchive::ZipArchive(const int fd, bool assume_ownership)
- : mapped_zip(fd),
+ZipArchive::ZipArchive(MappedZipFile&& map, bool assume_ownership)
+ : mapped_zip(map),
close_file(assume_ownership),
directory_offset(0),
central_directory(),
@@ -195,7 +101,8 @@
num_entries(0) {
#if defined(__BIONIC__)
if (assume_ownership) {
- android_fdsan_exchange_owner_tag(fd, 0, GetOwnerTag(this));
+ CHECK(mapped_zip.HasFd());
+ android_fdsan_exchange_owner_tag(mapped_zip.GetFileDescriptor(), 0, GetOwnerTag(this));
}
#endif
}
@@ -357,12 +264,12 @@
const size_t cd_length = archive->central_directory.GetMapLength();
const uint16_t num_entries = archive->num_entries;
- /*
- * Create hash table. We have a minimum 75% load factor, possibly as
- * low as 50% after we round off to a power of 2. There must be at
- * least one unused entry to avoid an infinite loop during creation.
- */
- archive->cd_entry_map = CdEntryMapZip32::Create(num_entries);
+ // TODO(xunchang) parse the zip64 Eocd
+ if (num_entries > UINT16_MAX) {
+ archive->cd_entry_map = CdEntryMapZip64::Create();
+ } else {
+ archive->cd_entry_map = CdEntryMapZip32::Create(num_entries);
+ }
if (archive->cd_entry_map == nullptr) {
return kAllocationFailed;
}
@@ -456,14 +363,32 @@
int32_t OpenArchiveFd(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
bool assume_ownership) {
- ZipArchive* archive = new ZipArchive(fd, assume_ownership);
+ ZipArchive* archive = new ZipArchive(MappedZipFile(fd), assume_ownership);
*handle = archive;
return OpenArchiveInternal(archive, debug_file_name);
}
+int32_t OpenArchiveFdRange(int fd, const char* debug_file_name, ZipArchiveHandle* handle,
+ off64_t length, off64_t offset, bool assume_ownership) {
+ ZipArchive* archive = new ZipArchive(MappedZipFile(fd, length, offset), assume_ownership);
+ *handle = archive;
+
+ if (length < 0) {
+ ALOGW("Invalid zip length %" PRId64, length);
+ return kIoError;
+ }
+
+ if (offset < 0) {
+ ALOGW("Invalid zip offset %" PRId64, offset);
+ return kIoError;
+ }
+
+ return OpenArchiveInternal(archive, debug_file_name);
+}
+
int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
const int fd = ::android::base::utf8::open(fileName, O_RDONLY | O_BINARY | O_CLOEXEC, 0);
- ZipArchive* archive = new ZipArchive(fd, true);
+ ZipArchive* archive = new ZipArchive(MappedZipFile(fd), true);
*handle = archive;
if (fd < 0) {
@@ -1120,24 +1045,14 @@
return ExtractToWriter(archive, entry, &writer);
}
-const char* ErrorCodeString(int32_t error_code) {
- // Make sure that the number of entries in kErrorMessages and ErrorCodes
- // match.
- static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
- "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
-
- const uint32_t idx = -error_code;
- if (idx < arraysize(kErrorMessages)) {
- return kErrorMessages[idx];
- }
-
- return "Unknown return code";
-}
-
int GetFileDescriptor(const ZipArchiveHandle archive) {
return archive->mapped_zip.GetFileDescriptor();
}
+off64_t GetFileDescriptorOffset(const ZipArchiveHandle archive) {
+ return archive->mapped_zip.GetFileOffset();
+}
+
#if !defined(_WIN32)
class ProcessWriter : public zip_archive::Writer {
public:
@@ -1177,31 +1092,65 @@
return base_ptr_;
}
+off64_t MappedZipFile::GetFileOffset() const {
+ return fd_offset_;
+}
+
off64_t MappedZipFile::GetFileLength() const {
if (has_fd_) {
- off64_t result = lseek64(fd_, 0, SEEK_END);
- if (result == -1) {
+ if (data_length_ != -1) {
+ return data_length_;
+ }
+ data_length_ = lseek64(fd_, 0, SEEK_END);
+ if (data_length_ == -1) {
ALOGE("Zip: lseek on fd %d failed: %s", fd_, strerror(errno));
}
- return result;
+ return data_length_;
} else {
if (base_ptr_ == nullptr) {
ALOGE("Zip: invalid file map");
return -1;
}
- return static_cast<off64_t>(data_length_);
+ return data_length_;
}
}
// Attempts to read |len| bytes into |buf| at offset |off|.
bool MappedZipFile::ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const {
if (has_fd_) {
- if (!android::base::ReadFullyAtOffset(fd_, buf, len, off)) {
+ if (off < 0) {
+ ALOGE("Zip: invalid offset %" PRId64, off);
+ return false;
+ }
+
+ off64_t read_offset;
+ if (__builtin_add_overflow(fd_offset_, off, &read_offset)) {
+ ALOGE("Zip: invalid read offset %" PRId64 " overflows, fd offset %" PRId64, off, fd_offset_);
+ return false;
+ }
+
+ if (data_length_ != -1) {
+ off64_t read_end;
+ if (len > std::numeric_limits<off64_t>::max() ||
+ __builtin_add_overflow(off, static_cast<off64_t>(len), &read_end)) {
+ ALOGE("Zip: invalid read length %" PRId64 " overflows, offset %" PRId64,
+ static_cast<off64_t>(len), off);
+ return false;
+ }
+
+ if (read_end > data_length_) {
+ ALOGE("Zip: invalid read length %" PRId64 " exceeds data length %" PRId64 ", offset %"
+ PRId64, static_cast<off64_t>(len), data_length_, off);
+ return false;
+ }
+ }
+
+ if (!android::base::ReadFullyAtOffset(fd_, buf, len, read_offset)) {
ALOGE("Zip: failed to read at offset %" PRId64, off);
return false;
}
} else {
- if (off < 0 || off > static_cast<off64_t>(data_length_)) {
+ if (off < 0 || off > data_length_) {
ALOGE("Zip: invalid offset: %" PRId64 ", data length: %" PRId64, off, data_length_);
return false;
}
@@ -1219,7 +1168,8 @@
bool ZipArchive::InitializeCentralDirectory(off64_t cd_start_offset, size_t cd_size) {
if (mapped_zip.HasFd()) {
directory_map = android::base::MappedFile::FromFd(mapped_zip.GetFileDescriptor(),
- cd_start_offset, cd_size, PROT_READ);
+ mapped_zip.GetFileOffset() + cd_start_offset,
+ cd_size, PROT_READ);
if (!directory_map) {
ALOGE("Zip: failed to map central directory (offset %" PRId64 ", size %zu): %s",
cd_start_offset, cd_size, strerror(errno));
diff --git a/libziparchive/zip_archive_private.h b/libziparchive/zip_archive_private.h
index 68977f6..3509b89 100644
--- a/libziparchive/zip_archive_private.h
+++ b/libziparchive/zip_archive_private.h
@@ -28,80 +28,20 @@
#include "android-base/macros.h"
#include "android-base/mapped_file.h"
-
-static const char* kErrorMessages[] = {
- "Success",
- "Iteration ended",
- "Zlib error",
- "Invalid file",
- "Invalid handle",
- "Duplicate entries in archive",
- "Empty archive",
- "Entry not found",
- "Invalid offset",
- "Inconsistent information",
- "Invalid entry name",
- "I/O error",
- "File mapping failed",
- "Allocation failed",
-};
-
-enum ErrorCodes : int32_t {
- kIterationEnd = -1,
-
- // We encountered a Zlib error when inflating a stream from this file.
- // Usually indicates file corruption.
- kZlibError = -2,
-
- // The input file cannot be processed as a zip archive. Usually because
- // it's too small, too large or does not have a valid signature.
- kInvalidFile = -3,
-
- // An invalid iteration / ziparchive handle was passed in as an input
- // argument.
- kInvalidHandle = -4,
-
- // The zip archive contained two (or possibly more) entries with the same
- // name.
- kDuplicateEntry = -5,
-
- // The zip archive contains no entries.
- kEmptyArchive = -6,
-
- // The specified entry was not found in the archive.
- kEntryNotFound = -7,
-
- // The zip archive contained an invalid local file header pointer.
- kInvalidOffset = -8,
-
- // The zip archive contained inconsistent entry information. This could
- // be because the central directory & local file header did not agree, or
- // if the actual uncompressed length or crc32 do not match their declared
- // values.
- kInconsistentInformation = -9,
-
- // An invalid entry name was encountered.
- kInvalidEntryName = -10,
-
- // An I/O related system call (read, lseek, ftruncate, map) failed.
- kIoError = -11,
-
- // We were not able to mmap the central directory or entry contents.
- kMmapFailed = -12,
-
- // An allocation failed.
- kAllocationFailed = -13,
-
- kLastErrorCode = kAllocationFailed,
-};
+#include "zip_cd_entry_map.h"
+#include "zip_error.h"
class MappedZipFile {
public:
explicit MappedZipFile(const int fd)
- : has_fd_(true), fd_(fd), base_ptr_(nullptr), data_length_(0) {}
+ : has_fd_(true), fd_(fd), fd_offset_(0), base_ptr_(nullptr), data_length_(-1) {}
+
+ explicit MappedZipFile(const int fd, off64_t length, off64_t offset)
+ : has_fd_(true), fd_(fd), fd_offset_(offset), base_ptr_(nullptr), data_length_(length) {}
explicit MappedZipFile(const void* address, size_t length)
- : has_fd_(false), fd_(-1), base_ptr_(address), data_length_(static_cast<off64_t>(length)) {}
+ : has_fd_(false), fd_(-1), fd_offset_(0), base_ptr_(address),
+ data_length_(static_cast<off64_t>(length)) {}
bool HasFd() const { return has_fd_; }
@@ -109,6 +49,8 @@
const void* GetBasePtr() const;
+ off64_t GetFileOffset() const;
+
off64_t GetFileLength() const;
bool ReadAtOffset(uint8_t* buf, size_t len, off64_t off) const;
@@ -121,9 +63,10 @@
const bool has_fd_;
const int fd_;
+ const off64_t fd_offset_;
const void* const base_ptr_;
- const off64_t data_length_;
+ mutable off64_t data_length_;
};
class CentralDirectory {
@@ -141,75 +84,6 @@
size_t length_;
};
-// This class is the interface of the central directory entries map. The map
-// helps to locate a particular cd entry based on the filename.
-class CdEntryMapInterface {
- public:
- virtual ~CdEntryMapInterface() = default;
- // Adds an entry to the map. The |name| should internally points to the
- // filename field of a cd entry. And |start| points to the beginning of the
- // central directory. Returns 0 on success.
- virtual int32_t AddToMap(std::string_view name, const uint8_t* start) = 0;
- // For the zip entry |entryName|, finds the offset of its filename field in
- // the central directory. Returns a pair of [status, offset]. The value of
- // the status is 0 on success.
- virtual std::pair<int32_t, uint64_t> GetCdEntryOffset(std::string_view name,
- const uint8_t* cd_start) const = 0;
- // Resets the iterator to the beginning of the map.
- virtual void ResetIteration() = 0;
- // Returns the [name, cd offset] of the current element. Also increments the
- // iterator to points to the next element. Returns an empty pair we have read
- // past boundary.
- virtual std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) = 0;
-};
-
-/**
- * More space efficient string representation of strings in an mmaped zipped
- * file than std::string_view. Using std::string_view as an entry in the
- * ZipArchive hash table wastes space. std::string_view stores a pointer to a
- * string (on 64 bit, 8 bytes) and the length to read from that pointer,
- * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
- * 6 bytes.
- *
- * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
- * mapped file instead of the entire address, consuming 8 bytes with alignment.
- */
-struct ZipStringOffset {
- uint32_t name_offset;
- uint16_t name_length;
-
- const std::string_view ToStringView(const uint8_t* start) const {
- return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
- }
-};
-
-// This implementation of CdEntryMap uses an array hash table. It uses less
-// memory than std::map; and it's used as the default implementation for zip
-// archives without zip64 extension.
-class CdEntryMapZip32 : public CdEntryMapInterface {
- public:
- static std::unique_ptr<CdEntryMapInterface> Create(uint16_t num_entries);
-
- int32_t AddToMap(std::string_view name, const uint8_t* start) override;
- std::pair<int32_t, uint64_t> GetCdEntryOffset(std::string_view name,
- const uint8_t* cd_start) const override;
- void ResetIteration() override;
- std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
-
- private:
- explicit CdEntryMapZip32(uint16_t num_entries);
-
- // We know how many entries are in the Zip archive, so we can have a
- // fixed-size hash table. We define a load factor of 0.75 and over
- // allocate so the maximum number entries can never be higher than
- // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
- uint32_t hash_table_size_{0};
- std::unique_ptr<ZipStringOffset[], decltype(&free)> hash_table_{nullptr, free};
-
- // The position of element for the current iteration.
- uint32_t current_position_{0};
-};
-
struct ZipArchive {
// open Zip archive
mutable MappedZipFile mapped_zip;
@@ -224,7 +98,7 @@
uint16_t num_entries;
std::unique_ptr<CdEntryMapInterface> cd_entry_map;
- ZipArchive(const int fd, bool assume_ownership);
+ ZipArchive(MappedZipFile&& map, bool assume_ownership);
ZipArchive(const void* address, size_t length);
~ZipArchive();
diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc
index 0916304..5caca8a 100644
--- a/libziparchive/zip_archive_test.cc
+++ b/libziparchive/zip_archive_test.cc
@@ -24,11 +24,14 @@
#include <unistd.h>
#include <memory>
+#include <set>
+#include <string_view>
#include <vector>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/mapped_file.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <gtest/gtest.h>
#include <ziparchive/zip_archive.h>
@@ -53,6 +56,76 @@
return OpenArchive(abs_path.c_str(), handle);
}
+class CdEntryMapTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ names_ = {
+ "a.txt", "b.txt", "b/", "b/c.txt", "b/d.txt",
+ };
+ separator_ = "separator";
+ header_ = "metadata";
+ joined_names_ = header_ + android::base::Join(names_, separator_);
+ base_ptr_ = reinterpret_cast<uint8_t*>(&joined_names_[0]);
+
+ entry_maps_.emplace_back(CdEntryMapZip32::Create(static_cast<uint16_t>(names_.size())));
+ entry_maps_.emplace_back(CdEntryMapZip64::Create());
+ for (auto& cd_map : entry_maps_) {
+ ASSERT_NE(nullptr, cd_map);
+ size_t offset = header_.size();
+ for (const auto& name : names_) {
+ auto status = cd_map->AddToMap(
+ std::string_view{joined_names_.c_str() + offset, name.size()}, base_ptr_);
+ ASSERT_EQ(0, status);
+ offset += name.size() + separator_.size();
+ }
+ }
+ }
+
+ std::vector<std::string> names_;
+ // A continuous region of memory serves as a mock of the central directory.
+ std::string joined_names_;
+ // We expect some metadata at the beginning of the central directory and between filenames.
+ std::string header_;
+ std::string separator_;
+
+ std::vector<std::unique_ptr<CdEntryMapInterface>> entry_maps_;
+ uint8_t* base_ptr_{nullptr}; // Points to the start of the central directory.
+};
+
+TEST_F(CdEntryMapTest, AddDuplicatedEntry) {
+ for (auto& cd_map : entry_maps_) {
+ std::string_view name = "b.txt";
+ ASSERT_NE(0, cd_map->AddToMap(name, base_ptr_));
+ }
+}
+
+TEST_F(CdEntryMapTest, FindEntry) {
+ for (auto& cd_map : entry_maps_) {
+ uint64_t expected_offset = header_.size();
+ for (const auto& name : names_) {
+ auto [status, offset] = cd_map->GetCdEntryOffset(name, base_ptr_);
+ ASSERT_EQ(status, kSuccess);
+ ASSERT_EQ(offset, expected_offset);
+ expected_offset += name.size() + separator_.size();
+ }
+ }
+}
+
+TEST_F(CdEntryMapTest, Iteration) {
+ std::set<std::string_view> expected(names_.begin(), names_.end());
+ for (auto& cd_map : entry_maps_) {
+ cd_map->ResetIteration();
+ std::set<std::string_view> entry_set;
+ auto ret = cd_map->Next(base_ptr_);
+ while (ret != std::pair<std::string_view, uint64_t>{}) {
+ auto [it, insert_status] = entry_set.insert(ret.first);
+ ASSERT_TRUE(insert_status);
+ ret = cd_map->Next(base_ptr_);
+ }
+ ASSERT_EQ(expected, entry_set);
+ }
+}
+
TEST(ziparchive, Open) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -108,6 +181,32 @@
close(fd);
}
+TEST(ziparchive, OpenAssumeFdRangeOwnership) {
+ int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
+ ASSERT_NE(-1, fd);
+ const off64_t length = lseek64(fd, 0, SEEK_END);
+ ASSERT_NE(-1, length);
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFdRange(fd, "OpenWithAssumeFdOwnership", &handle,
+ static_cast<size_t>(length), 0));
+ CloseArchive(handle);
+ ASSERT_EQ(-1, lseek(fd, 0, SEEK_SET));
+ ASSERT_EQ(EBADF, errno);
+}
+
+TEST(ziparchive, OpenDoNotAssumeFdRangeOwnership) {
+ int fd = open((test_data_dir + "/" + kValidZip).c_str(), O_RDONLY | O_BINARY);
+ ASSERT_NE(-1, fd);
+ const off64_t length = lseek(fd, 0, SEEK_END);
+ ASSERT_NE(-1, length);
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFdRange(fd, "OpenWithAssumeFdOwnership", &handle,
+ static_cast<size_t>(length), 0, false));
+ CloseArchive(handle);
+ ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
+ close(fd);
+}
+
TEST(ziparchive, Iteration_std_string_view) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
@@ -254,6 +353,48 @@
CloseArchive(handle);
}
+TEST(ziparchive, OpenArchiveFdRange) {
+ TemporaryFile tmp_file;
+ ASSERT_NE(-1, tmp_file.fd);
+
+ const std::string leading_garbage(21, 'x');
+ ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, leading_garbage.c_str(),
+ leading_garbage.size()));
+
+ std::string valid_content;
+ ASSERT_TRUE(android::base::ReadFileToString(test_data_dir + "/" + kValidZip, &valid_content));
+ ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, valid_content.c_str(), valid_content.size()));
+
+ const std::string ending_garbage(42, 'x');
+ ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, ending_garbage.c_str(),
+ ending_garbage.size()));
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, lseek(tmp_file.fd, 0, SEEK_SET));
+ ASSERT_EQ(0, OpenArchiveFdRange(tmp_file.fd, "OpenArchiveFdRange", &handle,
+ valid_content.size(),
+ static_cast<off64_t>(leading_garbage.size())));
+
+ // An entry that's deflated.
+ ZipEntry data;
+ ASSERT_EQ(0, FindEntry(handle, "a.txt", &data));
+ const uint32_t a_size = data.uncompressed_length;
+ ASSERT_EQ(a_size, kATxtContents.size());
+ auto buffer = std::unique_ptr<uint8_t[]>(new uint8_t[a_size]);
+ ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), a_size));
+ ASSERT_EQ(0, memcmp(buffer.get(), kATxtContents.data(), a_size));
+
+ // An entry that's stored.
+ ASSERT_EQ(0, FindEntry(handle, "b.txt", &data));
+ const uint32_t b_size = data.uncompressed_length;
+ ASSERT_EQ(b_size, kBTxtContents.size());
+ buffer = std::unique_ptr<uint8_t[]>(new uint8_t[b_size]);
+ ASSERT_EQ(0, ExtractToMemory(handle, &data, buffer.get(), b_size));
+ ASSERT_EQ(0, memcmp(buffer.get(), kBTxtContents.data(), b_size));
+
+ CloseArchive(handle);
+}
+
TEST(ziparchive, ExtractToMemory) {
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveWrapper(kValidZip, &handle));
diff --git a/libziparchive/zip_cd_entry_map.cc b/libziparchive/zip_cd_entry_map.cc
new file mode 100644
index 0000000..f187c06
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.cc
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#include "zip_cd_entry_map.h"
+
+#include <android-base/logging.h>
+#include <log/log.h>
+
+/*
+ * Round up to the next highest power of 2.
+ *
+ * Found on http://graphics.stanford.edu/~seander/bithacks.html.
+ */
+static uint32_t RoundUpPower2(uint32_t val) {
+ val--;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val++;
+
+ return val;
+}
+
+static uint32_t ComputeHash(std::string_view name) {
+ return static_cast<uint32_t>(std::hash<std::string_view>{}(name));
+}
+
+// Convert a ZipEntry to a hash table index, verifying that it's in a valid range.
+std::pair<ZipError, uint64_t> CdEntryMapZip32::GetCdEntryOffset(std::string_view name,
+ const uint8_t* start) const {
+ const uint32_t hash = ComputeHash(name);
+
+ // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
+ uint32_t ent = hash & (hash_table_size_ - 1);
+ while (hash_table_[ent].name_offset != 0) {
+ if (hash_table_[ent].ToStringView(start) == name) {
+ return {kSuccess, hash_table_[ent].name_offset};
+ }
+ ent = (ent + 1) & (hash_table_size_ - 1);
+ }
+
+ ALOGV("Zip: Unable to find entry %.*s", static_cast<int>(name.size()), name.data());
+ return {kEntryNotFound, 0};
+}
+
+ZipError CdEntryMapZip32::AddToMap(std::string_view name, const uint8_t* start) {
+ const uint64_t hash = ComputeHash(name);
+ uint32_t ent = hash & (hash_table_size_ - 1);
+
+ /*
+ * We over-allocated the table, so we're guaranteed to find an empty slot.
+ * Further, we guarantee that the hashtable size is not 0.
+ */
+ while (hash_table_[ent].name_offset != 0) {
+ if (hash_table_[ent].ToStringView(start) == name) {
+ // We've found a duplicate entry. We don't accept duplicates.
+ ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+ return kDuplicateEntry;
+ }
+ ent = (ent + 1) & (hash_table_size_ - 1);
+ }
+
+ // `name` has already been validated before entry.
+ const char* start_char = reinterpret_cast<const char*>(start);
+ hash_table_[ent].name_offset = static_cast<uint32_t>(name.data() - start_char);
+ hash_table_[ent].name_length = static_cast<uint16_t>(name.size());
+ return kSuccess;
+}
+
+void CdEntryMapZip32::ResetIteration() {
+ current_position_ = 0;
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip32::Next(const uint8_t* cd_start) {
+ while (current_position_ < hash_table_size_) {
+ const auto& entry = hash_table_[current_position_];
+ current_position_ += 1;
+
+ if (entry.name_offset != 0) {
+ return {entry.ToStringView(cd_start), entry.name_offset};
+ }
+ }
+ // We have reached the end of the hash table.
+ return {};
+}
+
+CdEntryMapZip32::CdEntryMapZip32(uint16_t num_entries) {
+ /*
+ * Create hash table. We have a minimum 75% load factor, possibly as
+ * low as 50% after we round off to a power of 2. There must be at
+ * least one unused entry to avoid an infinite loop during creation.
+ */
+ hash_table_size_ = RoundUpPower2(1 + (num_entries * 4) / 3);
+ hash_table_ = {
+ reinterpret_cast<ZipStringOffset*>(calloc(hash_table_size_, sizeof(ZipStringOffset))), free};
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip32::Create(uint16_t num_entries) {
+ auto entry_map = new CdEntryMapZip32(num_entries);
+ CHECK(entry_map->hash_table_ != nullptr)
+ << "Zip: unable to allocate the " << entry_map->hash_table_size_
+ << " entry hash_table, entry size: " << sizeof(ZipStringOffset);
+ return std::unique_ptr<CdEntryMapInterface>(entry_map);
+}
+
+std::unique_ptr<CdEntryMapInterface> CdEntryMapZip64::Create() {
+ return std::unique_ptr<CdEntryMapInterface>(new CdEntryMapZip64());
+}
+
+ZipError CdEntryMapZip64::AddToMap(std::string_view name, const uint8_t* start) {
+ const auto [it, added] =
+ entry_table_.insert({name, name.data() - reinterpret_cast<const char*>(start)});
+ if (!added) {
+ ALOGW("Zip: Found duplicate entry %.*s", static_cast<int>(name.size()), name.data());
+ return kDuplicateEntry;
+ }
+ return kSuccess;
+}
+
+std::pair<ZipError, uint64_t> CdEntryMapZip64::GetCdEntryOffset(std::string_view name,
+ const uint8_t* /*cd_start*/) const {
+ const auto it = entry_table_.find(name);
+ if (it == entry_table_.end()) {
+ ALOGV("Zip: Could not find entry %.*s", static_cast<int>(name.size()), name.data());
+ return {kEntryNotFound, 0};
+ }
+
+ return {kSuccess, it->second};
+}
+
+void CdEntryMapZip64::ResetIteration() {
+ iterator_ = entry_table_.begin();
+}
+
+std::pair<std::string_view, uint64_t> CdEntryMapZip64::Next(const uint8_t* /*cd_start*/) {
+ if (iterator_ == entry_table_.end()) {
+ return {};
+ }
+
+ return *iterator_++;
+}
diff --git a/libziparchive/zip_cd_entry_map.h b/libziparchive/zip_cd_entry_map.h
new file mode 100644
index 0000000..4957f75
--- /dev/null
+++ b/libziparchive/zip_cd_entry_map.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string_view>
+#include <utility>
+
+#include "zip_error.h"
+
+// This class is the interface of the central directory entries map. The map
+// helps to locate a particular cd entry based on the filename.
+class CdEntryMapInterface {
+ public:
+ virtual ~CdEntryMapInterface() = default;
+ // Adds an entry to the map. The |name| should internally points to the
+ // filename field of a cd entry. And |start| points to the beginning of the
+ // central directory. Returns 0 on success.
+ virtual ZipError AddToMap(std::string_view name, const uint8_t* start) = 0;
+ // For the zip entry |entryName|, finds the offset of its filename field in
+ // the central directory. Returns a pair of [status, offset]. The value of
+ // the status is 0 on success.
+ virtual std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const = 0;
+ // Resets the iterator to the beginning of the map.
+ virtual void ResetIteration() = 0;
+ // Returns the [name, cd offset] of the current element. Also increments the
+ // iterator to points to the next element. Returns an empty pair we have read
+ // past boundary.
+ virtual std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) = 0;
+};
+
+/**
+ * More space efficient string representation of strings in an mmaped zipped
+ * file than std::string_view. Using std::string_view as an entry in the
+ * ZipArchive hash table wastes space. std::string_view stores a pointer to a
+ * string (on 64 bit, 8 bytes) and the length to read from that pointer,
+ * 2 bytes. Because of alignment, the structure consumes 16 bytes, wasting
+ * 6 bytes.
+ *
+ * ZipStringOffset stores a 4 byte offset from a fixed location in the memory
+ * mapped file instead of the entire address, consuming 8 bytes with alignment.
+ */
+struct ZipStringOffset {
+ uint32_t name_offset;
+ uint16_t name_length;
+
+ const std::string_view ToStringView(const uint8_t* start) const {
+ return std::string_view{reinterpret_cast<const char*>(start + name_offset), name_length};
+ }
+};
+
+// This implementation of CdEntryMap uses an array hash table. It uses less
+// memory than std::map; and it's used as the default implementation for zip
+// archives without zip64 extension.
+class CdEntryMapZip32 : public CdEntryMapInterface {
+ public:
+ static std::unique_ptr<CdEntryMapInterface> Create(uint16_t num_entries);
+
+ ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+ std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const override;
+ void ResetIteration() override;
+ std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+ explicit CdEntryMapZip32(uint16_t num_entries);
+
+ // We know how many entries are in the Zip archive, so we can have a
+ // fixed-size hash table. We define a load factor of 0.75 and over
+ // allocate so the maximum number entries can never be higher than
+ // ((4 * UINT16_MAX) / 3 + 1) which can safely fit into a uint32_t.
+ uint32_t hash_table_size_{0};
+ std::unique_ptr<ZipStringOffset[], decltype(&free)> hash_table_{nullptr, free};
+
+ // The position of element for the current iteration.
+ uint32_t current_position_{0};
+};
+
+// This implementation of CdEntryMap uses a std::map
+class CdEntryMapZip64 : public CdEntryMapInterface {
+ public:
+ static std::unique_ptr<CdEntryMapInterface> Create();
+
+ ZipError AddToMap(std::string_view name, const uint8_t* start) override;
+ std::pair<ZipError, uint64_t> GetCdEntryOffset(std::string_view name,
+ const uint8_t* cd_start) const override;
+ void ResetIteration() override;
+ std::pair<std::string_view, uint64_t> Next(const uint8_t* cd_start) override;
+
+ private:
+ CdEntryMapZip64() = default;
+
+ std::map<std::string_view, uint64_t> entry_table_;
+
+ std::map<std::string_view, uint64_t>::iterator iterator_;
+};
diff --git a/libziparchive/zip_error.cpp b/libziparchive/zip_error.cpp
new file mode 100644
index 0000000..107ec47
--- /dev/null
+++ b/libziparchive/zip_error.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "zip_error.h"
+
+#include <android-base/macros.h>
+
+static const char* kErrorMessages[] = {
+ "Success",
+ "Iteration ended",
+ "Zlib error",
+ "Invalid file",
+ "Invalid handle",
+ "Duplicate entries in archive",
+ "Empty archive",
+ "Entry not found",
+ "Invalid offset",
+ "Inconsistent information",
+ "Invalid entry name",
+ "I/O error",
+ "File mapping failed",
+ "Allocation failed",
+};
+
+const char* ErrorCodeString(int32_t error_code) {
+ // Make sure that the number of entries in kErrorMessages and the ZipError
+ // enum match.
+ static_assert((-kLastErrorCode + 1) == arraysize(kErrorMessages),
+ "(-kLastErrorCode + 1) != arraysize(kErrorMessages)");
+
+ const uint32_t idx = -error_code;
+ if (idx < arraysize(kErrorMessages)) {
+ return kErrorMessages[idx];
+ }
+
+ return "Unknown return code";
+}
diff --git a/libziparchive/zip_error.h b/libziparchive/zip_error.h
new file mode 100644
index 0000000..37fd55f
--- /dev/null
+++ b/libziparchive/zip_error.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+enum ZipError : int32_t {
+ kSuccess = 0,
+
+ kIterationEnd = -1,
+
+ // We encountered a Zlib error when inflating a stream from this file.
+ // Usually indicates file corruption.
+ kZlibError = -2,
+
+ // The input file cannot be processed as a zip archive. Usually because
+ // it's too small, too large or does not have a valid signature.
+ kInvalidFile = -3,
+
+ // An invalid iteration / ziparchive handle was passed in as an input
+ // argument.
+ kInvalidHandle = -4,
+
+ // The zip archive contained two (or possibly more) entries with the same
+ // name.
+ kDuplicateEntry = -5,
+
+ // The zip archive contains no entries.
+ kEmptyArchive = -6,
+
+ // The specified entry was not found in the archive.
+ kEntryNotFound = -7,
+
+ // The zip archive contained an invalid local file header pointer.
+ kInvalidOffset = -8,
+
+ // The zip archive contained inconsistent entry information. This could
+ // be because the central directory & local file header did not agree, or
+ // if the actual uncompressed length or crc32 do not match their declared
+ // values.
+ kInconsistentInformation = -9,
+
+ // An invalid entry name was encountered.
+ kInvalidEntryName = -10,
+
+ // An I/O related system call (read, lseek, ftruncate, map) failed.
+ kIoError = -11,
+
+ // We were not able to mmap the central directory or entry contents.
+ kMmapFailed = -12,
+
+ // An allocation failed.
+ kAllocationFailed = -13,
+
+ kLastErrorCode = kAllocationFailed,
+};
diff --git a/storaged/main.cpp b/storaged/main.cpp
index a7bda14..bbed210 100644
--- a/storaged/main.cpp
+++ b/storaged/main.cpp
@@ -71,6 +71,7 @@
bool flag_dump_perf = false;
int opt;
+ signal(SIGPIPE, SIG_IGN);
android::base::InitLogging(argv, android::base::LogdLogger(android::base::SYSTEM));
for (;;) {