Merge "Create dir in /data for vendor customization"
diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp
index 5ee07cd..325210d 100644
--- a/debuggerd/libdebuggerd/test/tombstone_test.cpp
+++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp
@@ -77,7 +77,9 @@
resetLogs();
elf_set_fake_build_id("");
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = SIGABRT;
+ si.si_code = SI_KERNEL;
ptrace_set_fake_getsiginfo(si);
}
@@ -292,7 +294,9 @@
map_mock_->AddMap(map);
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = SIGBUS;
+ si.si_code = SI_KERNEL;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -348,7 +352,9 @@
map_mock_->AddMap(map);
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = SIGBUS;
+ si.si_code = SI_KERNEL;
si.si_addr = reinterpret_cast<void*>(0xa533000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -404,7 +410,9 @@
map_mock_->AddMap(map);
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = SIGBUS;
+ si.si_code = SI_KERNEL;
si.si_addr = reinterpret_cast<void*>(0xa534040);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -458,7 +466,9 @@
map_mock_->AddMap(map);
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = SIGBUS;
+ si.si_code = SI_KERNEL;
#if defined(__LP64__)
si.si_addr = reinterpret_cast<void*>(0x12345a534040UL);
#else
@@ -503,7 +513,7 @@
map_mock_->AddMap(map);
siginfo_t si;
- si.si_signo = 0;
+ memset(&si, 0, sizeof(si));
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -539,7 +549,9 @@
ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0);
siginfo_t si;
+ memset(&si, 0, sizeof(si));
si.si_signo = i;
+ si.si_code = SI_KERNEL;
si.si_addr = reinterpret_cast<void*>(0x1000);
ptrace_set_fake_getsiginfo(si);
dump_all_maps(backtrace_mock_.get(), map_mock_.get(), &log_, 100);
@@ -592,7 +604,7 @@
TEST_F(TombstoneTest, dump_signal_info_error) {
siginfo_t si;
- si.si_signo = 0;
+ memset(&si, 0, sizeof(si));
ptrace_set_fake_getsiginfo(si);
dump_signal_info(&log_, 123);
diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp
index c23da44..0c38449 100644
--- a/debuggerd/libdebuggerd/tombstone.cpp
+++ b/debuggerd/libdebuggerd/tombstone.cpp
@@ -283,7 +283,7 @@
if (BacktraceMap::IsValid(map) && !map.name.empty()) {
line += " " + map.name;
uintptr_t offset = 0;
- std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
+ std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset, &map));
if (!func_name.empty()) {
line += " (" + func_name;
if (offset) {
diff --git a/fs_mgr/fs_mgr_slotselect.cpp b/fs_mgr/fs_mgr_slotselect.cpp
index f3bba7b..a536b22 100644
--- a/fs_mgr/fs_mgr_slotselect.cpp
+++ b/fs_mgr/fs_mgr_slotselect.cpp
@@ -35,10 +35,11 @@
return -1;
}
got_suffix = 1;
+ // remove below line when bootloaders fix androidboot.slot_suffix param
+ if (suffix[0] == '_') suffix.erase(suffix.begin());
}
- if (asprintf(&tmp, "%s%s", fstab->recs[n].blk_device,
- suffix.c_str()) > 0) {
+ if (asprintf(&tmp, "%s_%s", fstab->recs[n].blk_device, suffix.c_str()) > 0) {
free(fstab->recs[n].blk_device);
fstab->recs[n].blk_device = tmp;
} else {
diff --git a/healthd/BatteryPropertiesRegistrar.cpp b/healthd/BatteryPropertiesRegistrar.cpp
index d28ba41..523e1f1 100644
--- a/healthd/BatteryPropertiesRegistrar.cpp
+++ b/healthd/BatteryPropertiesRegistrar.cpp
@@ -77,6 +77,10 @@
return healthd_get_property(id, val);
}
+void BatteryPropertiesRegistrar::scheduleUpdate() {
+ healthd_battery_update();
+}
+
status_t BatteryPropertiesRegistrar::dump(int fd, const Vector<String16>& /*args*/) {
IPCThreadState* self = IPCThreadState::self();
const int pid = self->getCallingPid();
diff --git a/healthd/BatteryPropertiesRegistrar.h b/healthd/BatteryPropertiesRegistrar.h
index 095f3d3..14e9145 100644
--- a/healthd/BatteryPropertiesRegistrar.h
+++ b/healthd/BatteryPropertiesRegistrar.h
@@ -32,6 +32,7 @@
public:
void publish(const sp<BatteryPropertiesRegistrar>& service);
void notifyListeners(const struct BatteryProperties& props);
+ void scheduleUpdate();
private:
Mutex mRegistrationLock;
diff --git a/include/backtrace/Backtrace.h b/include/backtrace/Backtrace.h
index c896ab8..4f73a65 100644
--- a/include/backtrace/Backtrace.h
+++ b/include/backtrace/Backtrace.h
@@ -104,8 +104,10 @@
virtual bool Unwind(size_t num_ignore_frames, ucontext_t* context = NULL) = 0;
// Get the function name and offset into the function given the pc.
- // If the string is empty, then no valid function name was found.
- virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);
+ // If the string is empty, then no valid function name was found,
+ // or the pc is not in any valid map.
+ virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset,
+ const backtrace_map_t* map = NULL);
// Fill in the map data associated with the given pc.
virtual void FillInMap(uintptr_t pc, backtrace_map_t* map);
diff --git a/include/backtrace/BacktraceMap.h b/include/backtrace/BacktraceMap.h
index df48dfe..8ab0dfa 100644
--- a/include/backtrace/BacktraceMap.h
+++ b/include/backtrace/BacktraceMap.h
@@ -33,6 +33,10 @@
#include <string>
#include <vector>
+// Special flag to indicate a map is in /dev/. However, a map in
+// /dev/ashmem/... does not set this flag.
+static constexpr int PROT_DEVICE_MAP = 0x8000;
+
struct backtrace_map_t {
uintptr_t start = 0;
uintptr_t end = 0;
diff --git a/include/ziparchive/zip_writer.h b/include/ziparchive/zip_writer.h
index 0b6ede4..41ca2e1 100644
--- a/include/ziparchive/zip_writer.h
+++ b/include/ziparchive/zip_writer.h
@@ -17,15 +17,16 @@
#ifndef LIBZIPARCHIVE_ZIPWRITER_H_
#define LIBZIPARCHIVE_ZIPWRITER_H_
-#include "android-base/macros.h"
-#include <utils/Compat.h>
-
#include <cstdio>
#include <ctime>
+#include <zlib.h>
+
#include <memory>
#include <string>
#include <vector>
-#include <zlib.h>
+
+#include "android-base/macros.h"
+#include "utils/Compat.h"
/**
* Writes a Zip file via a stateful interface.
@@ -63,6 +64,20 @@
kAlign32 = 0x02,
};
+ /**
+ * A struct representing a zip file entry.
+ */
+ struct FileEntry {
+ std::string path;
+ uint16_t compression_method;
+ uint32_t crc32;
+ uint32_t compressed_size;
+ uint32_t uncompressed_size;
+ uint16_t last_mod_time;
+ uint16_t last_mod_date;
+ uint32_t local_file_header_offset;
+ };
+
static const char* ErrorCodeString(int32_t error_code);
/**
@@ -122,6 +137,19 @@
int32_t FinishEntry();
/**
+ * Discards the last-written entry. Can only be called after an entry has been written using
+ * FinishEntry().
+ * Returns 0 on success, and an error value < 0 on failure.
+ */
+ int32_t DiscardLastEntry();
+
+ /**
+ * Sets `out_entry` to the last entry written after a call to FinishEntry().
+ * Returns 0 on success, and an error value < 0 if no entries have been written.
+ */
+ int32_t GetLastEntry(FileEntry* out_entry);
+
+ /**
* Writes the Central Directory Headers and flushes the zip file stream.
* Returns 0 on success, and an error value < 0 on failure.
*/
@@ -130,22 +158,11 @@
private:
DISALLOW_COPY_AND_ASSIGN(ZipWriter);
- struct FileInfo {
- std::string path;
- uint16_t compression_method;
- uint32_t crc32;
- uint32_t compressed_size;
- uint32_t uncompressed_size;
- uint16_t last_mod_time;
- uint16_t last_mod_date;
- uint32_t local_file_header_offset;
- };
-
int32_t HandleError(int32_t error_code);
int32_t PrepareDeflate();
- int32_t StoreBytes(FileInfo* file, const void* data, size_t len);
- int32_t CompressBytes(FileInfo* file, const void* data, size_t len);
- int32_t FlushCompressedBytes(FileInfo* file);
+ int32_t StoreBytes(FileEntry* file, const void* data, size_t len);
+ int32_t CompressBytes(FileEntry* file, const void* data, size_t len);
+ int32_t FlushCompressedBytes(FileEntry* file);
enum class State {
kWritingZip,
@@ -157,7 +174,8 @@
FILE* file_;
off64_t current_offset_;
State state_;
- std::vector<FileInfo> files_;
+ std::vector<FileEntry> files_;
+ FileEntry current_file_entry_;
std::unique_ptr<z_stream, void(*)(z_stream*)> z_stream_;
std::vector<uint8_t> buffer_;
diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp
index 0d2e11b..4354f0b 100644
--- a/libbacktrace/Backtrace.cpp
+++ b/libbacktrace/Backtrace.cpp
@@ -52,7 +52,16 @@
}
}
-std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset) {
+std::string Backtrace::GetFunctionName(uintptr_t pc, uintptr_t* offset, const backtrace_map_t* map) {
+ backtrace_map_t map_value;
+ if (map == nullptr) {
+ FillInMap(pc, &map_value);
+ map = &map_value;
+ }
+ // If no map is found, or this map is backed by a device, then return nothing.
+ if (map->start == 0 || (map->flags & PROT_DEVICE_MAP)) {
+ return "";
+ }
std::string func_name = GetFunctionNameRaw(pc, offset);
return func_name;
}
diff --git a/libbacktrace/UnwindCurrent.cpp b/libbacktrace/UnwindCurrent.cpp
index 4862d9d..3c509e6 100644
--- a/libbacktrace/UnwindCurrent.cpp
+++ b/libbacktrace/UnwindCurrent.cpp
@@ -127,7 +127,7 @@
if (num_ignore_frames == 0) {
// GetFunctionName is an expensive call, only do it if we are
// keeping the frame.
- frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+ frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
if (num_frames > 0) {
// Set the stack size for the previous frame.
backtrace_frame_data_t* prev = &frames_.at(num_frames-1);
@@ -143,6 +143,16 @@
frames_.resize(0);
}
}
+ // If the pc is in a device map, then don't try to step.
+ if (frame->map.flags & PROT_DEVICE_MAP) {
+ break;
+ }
+ // Verify the sp is not in a device map too.
+ backtrace_map_t map;
+ FillInMap(frame->sp, &map);
+ if (map.flags & PROT_DEVICE_MAP) {
+ break;
+ }
ret = unw_step (cursor.get());
} while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
diff --git a/libbacktrace/UnwindPtrace.cpp b/libbacktrace/UnwindPtrace.cpp
index 5c73bd6..42ac1bc 100644
--- a/libbacktrace/UnwindPtrace.cpp
+++ b/libbacktrace/UnwindPtrace.cpp
@@ -136,12 +136,28 @@
FillInMap(frame->pc, &frame->map);
- frame->func_name = GetFunctionName(frame->pc, &frame->func_offset);
+ frame->func_name = GetFunctionName(frame->pc, &frame->func_offset, &frame->map);
num_frames++;
+ // If the pc is in a device map, then don't try to step.
+ if (frame->map.flags & PROT_DEVICE_MAP) {
+ break;
+ }
} else {
+ // If the pc is in a device map, then don't try to step.
+ backtrace_map_t map;
+ FillInMap(pc, &map);
+ if (map.flags & PROT_DEVICE_MAP) {
+ break;
+ }
num_ignore_frames--;
}
+ // Verify the sp is not in a device map.
+ backtrace_map_t map;
+ FillInMap(sp, &map);
+ if (map.flags & PROT_DEVICE_MAP) {
+ break;
+ }
ret = unw_step (&cursor);
} while (ret > 0 && num_frames < MAX_BACKTRACE_FRAMES);
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp
index 9ca373a..24e48cd 100644
--- a/libbacktrace/backtrace_test.cpp
+++ b/libbacktrace/backtrace_test.cpp
@@ -42,6 +42,7 @@
#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>
+#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <cutils/atomic.h>
@@ -1436,6 +1437,171 @@
FinishRemoteProcess(pid);
}
+static void SetUcontextSp(uintptr_t sp, ucontext_t* ucontext) {
+#if defined(__arm__)
+ ucontext->uc_mcontext.arm_sp = sp;
+#elif defined(__aarch64__)
+ ucontext->uc_mcontext.sp = sp;
+#elif defined(__i386__)
+ ucontext->uc_mcontext.gregs[REG_ESP] = sp;
+#elif defined(__x86_64__)
+ ucontext->uc_mcontext.gregs[REG_RSP] = sp;
+#else
+ UNUSED(sp);
+ UNUSED(ucontext);
+ ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextPc(uintptr_t pc, ucontext_t* ucontext) {
+#if defined(__arm__)
+ ucontext->uc_mcontext.arm_pc = pc;
+#elif defined(__aarch64__)
+ ucontext->uc_mcontext.pc = pc;
+#elif defined(__i386__)
+ ucontext->uc_mcontext.gregs[REG_EIP] = pc;
+#elif defined(__x86_64__)
+ ucontext->uc_mcontext.gregs[REG_RIP] = pc;
+#else
+ UNUSED(pc);
+ UNUSED(ucontext);
+ ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static void SetUcontextLr(uintptr_t lr, ucontext_t* ucontext) {
+#if defined(__arm__)
+ ucontext->uc_mcontext.arm_lr = lr;
+#elif defined(__aarch64__)
+ ucontext->uc_mcontext.regs[30] = lr;
+#elif defined(__i386__)
+ // The lr is on the stack.
+ ASSERT_TRUE(lr != 0);
+ ASSERT_TRUE(ucontext != nullptr);
+#elif defined(__x86_64__)
+ // The lr is on the stack.
+ ASSERT_TRUE(lr != 0);
+ ASSERT_TRUE(ucontext != nullptr);
+#else
+ UNUSED(lr);
+ UNUSED(ucontext);
+ ASSERT_TRUE(false) << "Unsupported architecture";
+#endif
+}
+
+static constexpr size_t DEVICE_MAP_SIZE = 1024;
+
+static void SetupDeviceMap(void** device_map) {
+ // Make sure that anything in a device map will result in fails
+ // to read.
+ android::base::unique_fd device_fd(open("/dev/zero", O_RDONLY | O_CLOEXEC));
+
+ *device_map = mmap(nullptr, 1024, PROT_READ, MAP_PRIVATE, device_fd, 0);
+ ASSERT_TRUE(*device_map != MAP_FAILED);
+
+ // Make sure the map is readable.
+ ASSERT_EQ(0, reinterpret_cast<int*>(*device_map)[0]);
+}
+
+static void UnwindFromDevice(Backtrace* backtrace, void* device_map) {
+ uintptr_t device_map_uint = reinterpret_cast<uintptr_t>(device_map);
+
+ backtrace_map_t map;
+ backtrace->FillInMap(device_map_uint, &map);
+ // Verify the flag is set.
+ ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP);
+
+ // Quick sanity checks.
+ size_t offset;
+ ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset));
+ ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map));
+ ASSERT_EQ(std::string(""), backtrace->GetFunctionName(0, &offset));
+
+ uintptr_t cur_func_offset = reinterpret_cast<uintptr_t>(&test_level_one) + 1;
+ // Now verify the device map flag actually causes the function name to be empty.
+ backtrace->FillInMap(cur_func_offset, &map);
+ ASSERT_TRUE((map.flags & PROT_DEVICE_MAP) == 0);
+ ASSERT_NE(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+ map.flags |= PROT_DEVICE_MAP;
+ ASSERT_EQ(std::string(""), backtrace->GetFunctionName(cur_func_offset, &offset, &map));
+
+ ucontext_t ucontext;
+
+ // Create a context that has the pc in the device map, but the sp
+ // in a non-device map.
+ memset(&ucontext, 0, sizeof(ucontext));
+ SetUcontextSp(reinterpret_cast<uintptr_t>(&ucontext), &ucontext);
+ SetUcontextPc(device_map_uint, &ucontext);
+ SetUcontextLr(cur_func_offset, &ucontext);
+
+ ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+ // The buffer should only be a single element.
+ ASSERT_EQ(1U, backtrace->NumFrames());
+ const backtrace_frame_data_t* frame = backtrace->GetFrame(0);
+ ASSERT_EQ(device_map_uint, frame->pc);
+ ASSERT_EQ(reinterpret_cast<uintptr_t>(&ucontext), frame->sp);
+
+ // Check what happens when skipping the first frame.
+ ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+ ASSERT_EQ(0U, backtrace->NumFrames());
+
+ // Create a context that has the sp in the device map, but the pc
+ // in a non-device map.
+ memset(&ucontext, 0, sizeof(ucontext));
+ SetUcontextSp(device_map_uint, &ucontext);
+ SetUcontextPc(cur_func_offset, &ucontext);
+ SetUcontextLr(cur_func_offset, &ucontext);
+
+ ASSERT_TRUE(backtrace->Unwind(0, &ucontext));
+
+ // The buffer should only be a single element.
+ ASSERT_EQ(1U, backtrace->NumFrames());
+ frame = backtrace->GetFrame(0);
+ ASSERT_EQ(cur_func_offset, frame->pc);
+ ASSERT_EQ(device_map_uint, frame->sp);
+
+ // Check what happens when skipping the first frame.
+ ASSERT_TRUE(backtrace->Unwind(1, &ucontext));
+ ASSERT_EQ(0U, backtrace->NumFrames());
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_local) {
+ void* device_map;
+ SetupDeviceMap(&device_map);
+
+ // Now create an unwind object.
+ std::unique_ptr<Backtrace> backtrace(
+ Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD));
+ ASSERT_TRUE(backtrace);
+
+ UnwindFromDevice(backtrace.get(), device_map);
+
+ munmap(device_map, DEVICE_MAP_SIZE);
+}
+
+TEST(libbacktrace, unwind_disallow_device_map_remote) {
+ void* device_map;
+ SetupDeviceMap(&device_map);
+
+ // Fork a process to do a remote backtrace.
+ pid_t pid;
+ CreateRemoteProcess(&pid);
+
+ // Now create an unwind object.
+ std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, pid));
+
+ // TODO: Currently unwind from context doesn't work on remote
+ // unwind. Keep this test because the new unwinder should support
+ // this eventually, or we can delete this test.
+ // properly with unwind from context.
+ // UnwindFromDevice(backtrace.get(), device_map);
+
+ FinishRemoteProcess(pid);
+
+ munmap(device_map, DEVICE_MAP_SIZE);
+}
+
#if defined(ENABLE_PSS_TESTS)
#include "GetPss.h"
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index b72ed7f..ddd4dd5 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -14,21 +14,22 @@
* limitations under the License.
*/
-#include "entry_name_utils-inl.h"
-#include "zip_archive_common.h"
#include "ziparchive/zip_writer.h"
-#include <utils/Log.h>
-
-#include <sys/param.h>
-
-#include <cassert>
#include <cstdio>
-#include <memory>
-#include <vector>
+#include <sys/param.h>
#include <zlib.h>
#define DEF_MEM_LEVEL 8 // normally in zutil.h?
+#include <memory>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "utils/Log.h"
+
+#include "entry_name_utils-inl.h"
+#include "zip_archive_common.h"
+
#if !defined(powerof2)
#define powerof2(x) ((((x)-1)&(x))==0)
#endif
@@ -171,12 +172,12 @@
return kInvalidAlignment;
}
- FileInfo fileInfo = {};
- fileInfo.path = std::string(path);
- fileInfo.local_file_header_offset = current_offset_;
+ current_file_entry_ = {};
+ current_file_entry_.path = path;
+ current_file_entry_.local_file_header_offset = current_offset_;
- if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(fileInfo.path.data()),
- fileInfo.path.size())) {
+ if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(current_file_entry_.path.data()),
+ current_file_entry_.path.size())) {
return kInvalidEntryName;
}
@@ -188,24 +189,24 @@
header.gpb_flags |= kGPBDDFlagMask;
if (flags & ZipWriter::kCompress) {
- fileInfo.compression_method = kCompressDeflated;
+ current_file_entry_.compression_method = kCompressDeflated;
int32_t result = PrepareDeflate();
if (result != kNoError) {
return result;
}
} else {
- fileInfo.compression_method = kCompressStored;
+ current_file_entry_.compression_method = kCompressStored;
}
- header.compression_method = fileInfo.compression_method;
+ header.compression_method = current_file_entry_.compression_method;
- ExtractTimeAndDate(time, &fileInfo.last_mod_time, &fileInfo.last_mod_date);
- header.last_mod_time = fileInfo.last_mod_time;
- header.last_mod_date = fileInfo.last_mod_date;
+ ExtractTimeAndDate(time, ¤t_file_entry_.last_mod_time, ¤t_file_entry_.last_mod_date);
+ header.last_mod_time = current_file_entry_.last_mod_time;
+ header.last_mod_date = current_file_entry_.last_mod_date;
- header.file_name_length = fileInfo.path.size();
+ header.file_name_length = current_file_entry_.path.size();
- off64_t offset = current_offset_ + sizeof(header) + fileInfo.path.size();
+ off64_t offset = current_offset_ + sizeof(header) + current_file_entry_.path.size();
std::vector<char> zero_padding;
if (alignment != 0 && (offset & (alignment - 1))) {
// Pad the extra field so the data will be aligned.
@@ -220,7 +221,8 @@
return HandleError(kIoError);
}
- if (fwrite(path, sizeof(*path), fileInfo.path.size(), file_) != fileInfo.path.size()) {
+ if (fwrite(path, sizeof(*path), current_file_entry_.path.size(), file_)
+ != current_file_entry_.path.size()) {
return HandleError(kIoError);
}
@@ -230,15 +232,37 @@
return HandleError(kIoError);
}
- files_.emplace_back(std::move(fileInfo));
-
current_offset_ = offset;
state_ = State::kWritingEntry;
return kNoError;
}
+int32_t ZipWriter::DiscardLastEntry() {
+ if (state_ != State::kWritingZip || files_.empty()) {
+ return kInvalidState;
+ }
+
+ FileEntry& last_entry = files_.back();
+ current_offset_ = last_entry.local_file_header_offset;
+ if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
+ return HandleError(kIoError);
+ }
+ files_.pop_back();
+ return kNoError;
+}
+
+int32_t ZipWriter::GetLastEntry(FileEntry* out_entry) {
+ CHECK(out_entry != nullptr);
+
+ if (files_.empty()) {
+ return kInvalidState;
+ }
+ *out_entry = files_.back();
+ return kNoError;
+}
+
int32_t ZipWriter::PrepareDeflate() {
- assert(state_ == State::kWritingZip);
+ CHECK(state_ == State::kWritingZip);
// Initialize the z_stream for compression.
z_stream_ = std::unique_ptr<z_stream, void(*)(z_stream*)>(new z_stream(), DeleteZStream);
@@ -269,25 +293,25 @@
return HandleError(kInvalidState);
}
- FileInfo& currentFile = files_.back();
int32_t result = kNoError;
- if (currentFile.compression_method & kCompressDeflated) {
- result = CompressBytes(¤tFile, data, len);
+ if (current_file_entry_.compression_method & kCompressDeflated) {
+ result = CompressBytes(¤t_file_entry_, data, len);
} else {
- result = StoreBytes(¤tFile, data, len);
+ result = StoreBytes(¤t_file_entry_, data, len);
}
if (result != kNoError) {
return result;
}
- currentFile.crc32 = crc32(currentFile.crc32, reinterpret_cast<const Bytef*>(data), len);
- currentFile.uncompressed_size += len;
+ current_file_entry_.crc32 = crc32(current_file_entry_.crc32,
+ reinterpret_cast<const Bytef*>(data), len);
+ current_file_entry_.uncompressed_size += len;
return kNoError;
}
-int32_t ZipWriter::StoreBytes(FileInfo* file, const void* data, size_t len) {
- assert(state_ == State::kWritingEntry);
+int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, size_t len) {
+ CHECK(state_ == State::kWritingEntry);
if (fwrite(data, 1, len, file_) != len) {
return HandleError(kIoError);
@@ -297,11 +321,11 @@
return kNoError;
}
-int32_t ZipWriter::CompressBytes(FileInfo* file, const void* data, size_t len) {
- assert(state_ == State::kWritingEntry);
- assert(z_stream_);
- assert(z_stream_->next_out != nullptr);
- assert(z_stream_->avail_out != 0);
+int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, size_t len) {
+ CHECK(state_ == State::kWritingEntry);
+ CHECK(z_stream_);
+ CHECK(z_stream_->next_out != nullptr);
+ CHECK(z_stream_->avail_out != 0);
// Prepare the input.
z_stream_->next_in = reinterpret_cast<const uint8_t*>(data);
@@ -331,17 +355,17 @@
return kNoError;
}
-int32_t ZipWriter::FlushCompressedBytes(FileInfo* file) {
- assert(state_ == State::kWritingEntry);
- assert(z_stream_);
- assert(z_stream_->next_out != nullptr);
- assert(z_stream_->avail_out != 0);
+int32_t ZipWriter::FlushCompressedBytes(FileEntry* file) {
+ CHECK(state_ == State::kWritingEntry);
+ CHECK(z_stream_);
+ CHECK(z_stream_->next_out != nullptr);
+ CHECK(z_stream_->avail_out != 0);
// Keep deflating while there isn't enough space in the buffer to
// to complete the compress.
int zerr;
while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
- assert(z_stream_->avail_out == 0);
+ CHECK(z_stream_->avail_out == 0);
size_t write_bytes = z_stream_->next_out - buffer_.data();
if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
return HandleError(kIoError);
@@ -373,9 +397,8 @@
return kInvalidState;
}
- FileInfo& currentFile = files_.back();
- if (currentFile.compression_method & kCompressDeflated) {
- int32_t result = FlushCompressedBytes(¤tFile);
+ if (current_file_entry_.compression_method & kCompressDeflated) {
+ int32_t result = FlushCompressedBytes(¤t_file_entry_);
if (result != kNoError) {
return result;
}
@@ -388,13 +411,15 @@
}
DataDescriptor dd = {};
- dd.crc32 = currentFile.crc32;
- dd.compressed_size = currentFile.compressed_size;
- dd.uncompressed_size = currentFile.uncompressed_size;
+ dd.crc32 = current_file_entry_.crc32;
+ dd.compressed_size = current_file_entry_.compressed_size;
+ dd.uncompressed_size = current_file_entry_.uncompressed_size;
if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
return HandleError(kIoError);
}
+ files_.emplace_back(std::move(current_file_entry_));
+
current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
state_ = State::kWritingZip;
return kNoError;
@@ -406,7 +431,7 @@
}
off64_t startOfCdr = current_offset_;
- for (FileInfo& file : files_) {
+ for (FileEntry& file : files_) {
CentralDirectoryRecord cdr = {};
cdr.record_signature = CentralDirectoryRecord::kSignature;
cdr.gpb_flags |= kGPBDDFlagMask;
@@ -442,11 +467,19 @@
return HandleError(kIoError);
}
+ current_offset_ += sizeof(er);
+
+ // Since we can BackUp() and potentially finish writing at an offset less than one we had
+ // already written at, we must truncate the file.
+
+ if (ftruncate64(fileno(file_), current_offset_) != 0) {
+ return HandleError(kIoError);
+ }
+
if (fflush(file_) != 0) {
return HandleError(kIoError);
}
- current_offset_ += sizeof(er);
state_ = State::kDone;
return kNoError;
}
diff --git a/libziparchive/zip_writer_test.cc b/libziparchive/zip_writer_test.cc
index 16a574d..259bcff 100644
--- a/libziparchive/zip_writer_test.cc
+++ b/libziparchive/zip_writer_test.cc
@@ -23,6 +23,10 @@
#include <memory>
#include <vector>
+static ::testing::AssertionResult AssertFileEntryContentsEq(const std::string& expected,
+ ZipArchiveHandle handle,
+ ZipEntry* zip_entry);
+
struct zipwriter : public ::testing::Test {
TemporaryFile* temp_file_;
int fd_;
@@ -59,16 +63,10 @@
ZipEntry data;
ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
- EXPECT_EQ(strlen(expected), data.compressed_length);
- EXPECT_EQ(strlen(expected), data.uncompressed_length);
EXPECT_EQ(kCompressStored, data.method);
-
- char buffer[6];
- EXPECT_EQ(0,
- ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(&buffer), sizeof(buffer)));
- buffer[5] = 0;
-
- EXPECT_STREQ(expected, buffer);
+ EXPECT_EQ(strlen(expected), data.compressed_length);
+ ASSERT_EQ(strlen(expected), data.uncompressed_length);
+ ASSERT_TRUE(AssertFileEntryContentsEq(expected, handle, &data));
CloseArchive(handle);
}
@@ -94,26 +92,19 @@
ZipArchiveHandle handle;
ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
- char buffer[4];
ZipEntry data;
ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
EXPECT_EQ(kCompressStored, data.method);
EXPECT_EQ(2u, data.compressed_length);
- EXPECT_EQ(2u, data.uncompressed_length);
- ASSERT_EQ(0,
- ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
- buffer[2] = 0;
- EXPECT_STREQ("he", buffer);
+ ASSERT_EQ(2u, data.uncompressed_length);
+ ASSERT_TRUE(AssertFileEntryContentsEq("he", handle, &data));
ASSERT_EQ(0, FindEntry(handle, ZipString("file/file.txt"), &data));
EXPECT_EQ(kCompressStored, data.method);
EXPECT_EQ(3u, data.compressed_length);
- EXPECT_EQ(3u, data.uncompressed_length);
- ASSERT_EQ(0,
- ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
- buffer[3] = 0;
- EXPECT_STREQ("llo", buffer);
+ ASSERT_EQ(3u, data.uncompressed_length);
+ ASSERT_TRUE(AssertFileEntryContentsEq("llo", handle, &data));
ASSERT_EQ(0, FindEntry(handle, ZipString("file/file2.txt"), &data));
EXPECT_EQ(kCompressStored, data.method);
@@ -143,7 +134,7 @@
CloseArchive(handle);
}
-void ConvertZipTimeToTm(uint32_t& zip_time, struct tm* tm) {
+static void ConvertZipTimeToTm(uint32_t& zip_time, struct tm* tm) {
memset(tm, 0, sizeof(struct tm));
tm->tm_hour = (zip_time >> 11) & 0x1f;
tm->tm_min = (zip_time >> 5) & 0x3f;
@@ -264,14 +255,8 @@
ZipEntry data;
ASSERT_EQ(0, FindEntry(handle, ZipString("file.txt"), &data));
EXPECT_EQ(kCompressDeflated, data.method);
- EXPECT_EQ(4u, data.uncompressed_length);
-
- char buffer[5];
- ASSERT_EQ(0,
- ExtractToMemory(handle, &data, reinterpret_cast<uint8_t*>(buffer), arraysize(buffer)));
- buffer[4] = 0;
-
- EXPECT_STREQ("helo", buffer);
+ ASSERT_EQ(4u, data.uncompressed_length);
+ ASSERT_TRUE(AssertFileEntryContentsEq("helo", handle, &data));
CloseArchive(handle);
}
@@ -319,3 +304,111 @@
ASSERT_EQ(-5, writer.StartAlignedEntry("align.txt", ZipWriter::kAlign32, 4096));
ASSERT_EQ(-6, writer.StartAlignedEntry("align.txt", 0, 3));
}
+
+TEST_F(zipwriter, BackupRemovesTheLastFile) {
+ ZipWriter writer(file_);
+
+ const char* kKeepThis = "keep this";
+ const char* kDropThis = "drop this";
+ const char* kReplaceWithThis = "replace with this";
+
+ ZipWriter::FileEntry entry;
+ EXPECT_LT(writer.GetLastEntry(&entry), 0);
+
+ ASSERT_EQ(0, writer.StartEntry("keep.txt", 0));
+ ASSERT_EQ(0, writer.WriteBytes(kKeepThis, strlen(kKeepThis)));
+ ASSERT_EQ(0, writer.FinishEntry());
+
+ ASSERT_EQ(0, writer.GetLastEntry(&entry));
+ EXPECT_EQ("keep.txt", entry.path);
+
+ ASSERT_EQ(0, writer.StartEntry("drop.txt", 0));
+ ASSERT_EQ(0, writer.WriteBytes(kDropThis, strlen(kDropThis)));
+ ASSERT_EQ(0, writer.FinishEntry());
+
+ ASSERT_EQ(0, writer.GetLastEntry(&entry));
+ EXPECT_EQ("drop.txt", entry.path);
+
+ ASSERT_EQ(0, writer.DiscardLastEntry());
+
+ ASSERT_EQ(0, writer.GetLastEntry(&entry));
+ EXPECT_EQ("keep.txt", entry.path);
+
+ ASSERT_EQ(0, writer.StartEntry("replace.txt", 0));
+ ASSERT_EQ(0, writer.WriteBytes(kReplaceWithThis, strlen(kReplaceWithThis)));
+ ASSERT_EQ(0, writer.FinishEntry());
+
+ ASSERT_EQ(0, writer.GetLastEntry(&entry));
+ EXPECT_EQ("replace.txt", entry.path);
+
+ ASSERT_EQ(0, writer.Finish());
+
+ // Verify that "drop.txt" does not exist.
+
+ ASSERT_GE(0, lseek(fd_, 0, SEEK_SET));
+
+ ZipArchiveHandle handle;
+ ASSERT_EQ(0, OpenArchiveFd(fd_, "temp", &handle, false));
+
+ ZipEntry data;
+ ASSERT_EQ(0, FindEntry(handle, ZipString("keep.txt"), &data));
+ ASSERT_TRUE(AssertFileEntryContentsEq(kKeepThis, handle, &data));
+
+ ASSERT_NE(0, FindEntry(handle, ZipString("drop.txt"), &data));
+
+ ASSERT_EQ(0, FindEntry(handle, ZipString("replace.txt"), &data));
+ ASSERT_TRUE(AssertFileEntryContentsEq(kReplaceWithThis, handle, &data));
+
+ CloseArchive(handle);
+}
+
+TEST_F(zipwriter, TruncateFileAfterBackup) {
+ ZipWriter writer(file_);
+
+ const char* kSmall = "small";
+
+ ASSERT_EQ(0, writer.StartEntry("small.txt", 0));
+ ASSERT_EQ(0, writer.WriteBytes(kSmall, strlen(kSmall)));
+ ASSERT_EQ(0, writer.FinishEntry());
+
+ ASSERT_EQ(0, writer.StartEntry("large.txt", 0));
+ std::vector<uint8_t> data;
+ data.resize(1024*1024, 0xef);
+ ASSERT_EQ(0, writer.WriteBytes(data.data(), data.size()));
+ ASSERT_EQ(0, writer.FinishEntry());
+
+ off64_t before_len = ftello64(file_);
+
+ ZipWriter::FileEntry entry;
+ ASSERT_EQ(0, writer.GetLastEntry(&entry));
+ ASSERT_EQ(0, writer.DiscardLastEntry());
+
+ ASSERT_EQ(0, writer.Finish());
+
+ off64_t after_len = ftello64(file_);
+
+ ASSERT_GT(before_len, after_len);
+}
+
+static ::testing::AssertionResult AssertFileEntryContentsEq(const std::string& expected,
+ ZipArchiveHandle handle,
+ ZipEntry* zip_entry) {
+ if (expected.size() != zip_entry->uncompressed_length) {
+ return ::testing::AssertionFailure() << "uncompressed entry size "
+ << zip_entry->uncompressed_length << " does not match expected size " << expected.size();
+ }
+
+ std::string actual;
+ actual.resize(expected.size());
+
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(&*actual.begin());
+ if (ExtractToMemory(handle, zip_entry, buffer, actual.size()) != 0) {
+ return ::testing::AssertionFailure() << "failed to extract entry";
+ }
+
+ if (expected != actual) {
+ return ::testing::AssertionFailure() << "actual zip_entry data '" << actual
+ << "' does not match expected '" << expected << "'";
+ }
+ return ::testing::AssertionSuccess();
+}
diff --git a/logwrapper/Android.bp b/logwrapper/Android.bp
index 7ee0464..ccb1aa6 100644
--- a/logwrapper/Android.bp
+++ b/logwrapper/Android.bp
@@ -32,3 +32,22 @@
"-Werror",
],
}
+
+// ========================================================
+// Benchmark
+// ========================================================
+cc_benchmark {
+ name: "android_fork_execvp_ext_benchmark",
+ srcs: [
+ "android_fork_execvp_ext_benchmark.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ "libcutils",
+ "liblog",
+ "liblogwrap",
+ ],
+ cflags: [
+ "-Werror",
+ ]
+}
diff --git a/logwrapper/android_fork_execvp_ext_benchmark.cpp b/logwrapper/android_fork_execvp_ext_benchmark.cpp
new file mode 100644
index 0000000..1abd932
--- /dev/null
+++ b/logwrapper/android_fork_execvp_ext_benchmark.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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 "logwrap/logwrap.h"
+
+#include <android-base/logging.h>
+#include <benchmark/benchmark.h>
+
+static void BM_android_fork_execvp_ext(benchmark::State& state) {
+ const char* argv[] = {"/system/bin/echo", "hello", "world"};
+ const int argc = 3;
+ while (state.KeepRunning()) {
+ int rc = android_fork_execvp_ext(
+ argc, (char**)argv, NULL /* status */, false /* ignore_int_quit */, LOG_NONE,
+ false /* abbreviated */, NULL /* file_path */, NULL /* opts */, 0 /* opts_len */);
+ CHECK_EQ(0, rc);
+ }
+}
+BENCHMARK(BM_android_fork_execvp_ext);
+
+BENCHMARK_MAIN();
diff --git a/logwrapper/include/logwrap/logwrap.h b/logwrapper/include/logwrap/logwrap.h
index 89a8fdd..d3538b3 100644
--- a/logwrapper/include/logwrap/logwrap.h
+++ b/logwrapper/include/logwrap/logwrap.h
@@ -54,9 +54,8 @@
* the specified log until the child has exited.
* file_path: if log_target has the LOG_FILE bit set, then this parameter
* must be set to the pathname of the file to log to.
- * opts: set to non-NULL if you want to use one or more of the
- * FORK_EXECVP_OPTION_* features.
- * opts_len: the length of the opts array. When opts is NULL, pass 0.
+ * unused_opts: currently unused.
+ * unused_opts_len: currently unused.
*
* Return value:
* 0 when logwrap successfully run the child process and captured its status
@@ -72,30 +71,10 @@
#define LOG_KLOG 2
#define LOG_FILE 4
-/* Write data to child's stdin. */
-#define FORK_EXECVP_OPTION_INPUT 0
-/* Capture data from child's stdout and stderr. */
-#define FORK_EXECVP_OPTION_CAPTURE_OUTPUT 1
-
-struct AndroidForkExecvpOption {
- int opt_type;
- union {
- struct {
- const uint8_t* input;
- size_t input_len;
- } opt_input;
- struct {
- void (*on_output)(const uint8_t* /*output*/,
- size_t /*output_len*/,
- void* /* user_pointer */);
- void* user_pointer;
- } opt_capture_output;
- };
-};
-
+// TODO: Remove unused_opts / unused_opts_len in a followup change.
int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
- int log_target, bool abbreviated, char *file_path,
- const struct AndroidForkExecvpOption* opts, size_t opts_len);
+ int log_target, bool abbreviated, char *file_path, void* unused_opts,
+ int unused_opts_len);
/* Similar to above, except abbreviated logging is not available, and if logwrap
* is true, logging is to the Android system log, and if false, there is no
diff --git a/logwrapper/logwrap.c b/logwrapper/logwrap.c
index 3ad0983..7076078 100644
--- a/logwrapper/logwrap.c
+++ b/logwrapper/logwrap.c
@@ -291,8 +291,7 @@
}
static int parent(const char *tag, int parent_read, pid_t pid,
- int *chld_sts, int log_target, bool abbreviated, char *file_path,
- const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+ int *chld_sts, int log_target, bool abbreviated, char *file_path) {
int status = 0;
char buffer[4096];
struct pollfd poll_fds[] = {
@@ -359,13 +358,6 @@
sz = TEMP_FAILURE_RETRY(
read(parent_read, &buffer[b], sizeof(buffer) - 1 - b));
- for (size_t i = 0; sz > 0 && i < opts_len; ++i) {
- if (opts[i].opt_type == FORK_EXECVP_OPTION_CAPTURE_OUTPUT) {
- opts[i].opt_capture_output.on_output(
- (uint8_t*)&buffer[b], sz, opts[i].opt_capture_output.user_pointer);
- }
- }
-
sz += b;
// Log one line at a time
for (b = 0; b < sz; b++) {
@@ -483,7 +475,7 @@
int android_fork_execvp_ext(int argc, char* argv[], int *status, bool ignore_int_quit,
int log_target, bool abbreviated, char *file_path,
- const struct AndroidForkExecvpOption* opts, size_t opts_len) {
+ void *unused_opts, int unused_opts_len) {
pid_t pid;
int parent_ptty;
int child_ptty;
@@ -493,6 +485,9 @@
sigset_t oldset;
int rc = 0;
+ LOG_ALWAYS_FATAL_IF(unused_opts != NULL);
+ LOG_ALWAYS_FATAL_IF(unused_opts_len != 0);
+
rc = pthread_mutex_lock(&fd_mutex);
if (rc) {
ERROR("failed to lock signal_fd mutex\n");
@@ -538,13 +533,6 @@
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
close(parent_ptty);
- // redirect stdin, stdout and stderr
- for (size_t i = 0; i < opts_len; ++i) {
- if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
- dup2(child_ptty, 0);
- break;
- }
- }
dup2(child_ptty, 1);
dup2(child_ptty, 2);
close(child_ptty);
@@ -561,24 +549,8 @@
sigaction(SIGQUIT, &ignact, &quitact);
}
- for (size_t i = 0; i < opts_len; ++i) {
- if (opts[i].opt_type == FORK_EXECVP_OPTION_INPUT) {
- size_t left = opts[i].opt_input.input_len;
- const uint8_t* input = opts[i].opt_input.input;
- while (left > 0) {
- ssize_t res =
- TEMP_FAILURE_RETRY(write(parent_ptty, input, left));
- if (res < 0) {
- break;
- }
- left -= res;
- input += res;
- }
- }
- }
-
rc = parent(argv[0], parent_ptty, pid, status, log_target,
- abbreviated, file_path, opts, opts_len);
+ abbreviated, file_path);
}
if (ignore_int_quit) {
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 0045fd6..ad5647b 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -346,6 +346,9 @@
# create the lost+found directories, so as to enforce our permissions
mkdir /cache/lost+found 0770 root root
+on late-fs
+ start hwservicemanager
+
on post-fs-data
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
@@ -589,8 +592,9 @@
# Define default initial receive window size in segments.
setprop net.tcp.default_init_rwnd 60
- # Start all binderized HAL daemons
- start hwservicemanager
+ # Start standard binderized HAL daemons
+ class_start hal
+
class_start core
on nonencrypted