Merge "fs_mgr: retrofit VAB update after A/B calc COW space."
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp
index 4ba1c49..6faead0 100644
--- a/fs_mgr/fs_mgr.cpp
+++ b/fs_mgr/fs_mgr.cpp
@@ -888,6 +888,17 @@
public:
CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {}
+ bool NeedsCheckpoint() {
+ if (needs_checkpoint_ != UNKNOWN) {
+ return needs_checkpoint_ == YES;
+ }
+ if (!call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
+ LERROR << "Failed to find if checkpointing is needed. Assuming no.";
+ needs_checkpoint_ = NO;
+ }
+ return needs_checkpoint_ == YES;
+ }
+
bool Update(FstabEntry* entry, const std::string& block_device = std::string()) {
if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
return true;
@@ -897,13 +908,7 @@
call_vdc({"checkpoint", "restoreCheckpoint", entry->blk_device}, nullptr);
}
- if (needs_checkpoint_ == UNKNOWN &&
- !call_vdc({"checkpoint", "needsCheckpoint"}, &needs_checkpoint_)) {
- LERROR << "Failed to find if checkpointing is needed. Assuming no.";
- needs_checkpoint_ = NO;
- }
-
- if (needs_checkpoint_ != YES) {
+ if (!NeedsCheckpoint()) {
return true;
}
@@ -1324,6 +1329,69 @@
return ret;
}
+static std::string GetUserdataBlockDevice() {
+ Fstab fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ LERROR << "Failed to read /proc/mounts";
+ return "";
+ }
+ auto entry = GetEntryForMountPoint(&fstab, "/data");
+ if (entry == nullptr) {
+ LERROR << "Didn't find /data mount point in /proc/mounts";
+ return "";
+ }
+ return entry->blk_device;
+}
+
+int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
+ const std::string& block_device = GetUserdataBlockDevice();
+ LINFO << "Userdata is mounted on " << block_device;
+ auto entry = std::find_if(fstab->begin(), fstab->end(), [&block_device](const FstabEntry& e) {
+ if (e.mount_point != "/data") {
+ return false;
+ }
+ if (e.blk_device == block_device) {
+ return true;
+ }
+ DeviceMapper& dm = DeviceMapper::Instance();
+ std::string path;
+ if (!dm.GetDmDevicePathByName("userdata", &path)) {
+ return false;
+ }
+ return path == block_device;
+ });
+ if (entry == fstab->end()) {
+ LERROR << "Can't find /data in fstab";
+ return -1;
+ }
+ if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) {
+ LINFO << "Userdata doesn't support checkpointing. Nothing to do";
+ return 0;
+ }
+ CheckpointManager checkpoint_manager;
+ if (!checkpoint_manager.NeedsCheckpoint()) {
+ LINFO << "Checkpointing not needed. Don't remount";
+ return 0;
+ }
+ if (entry->fs_mgr_flags.checkpoint_fs) {
+ // Userdata is f2fs, simply remount it.
+ if (!checkpoint_manager.Update(&(*entry))) {
+ LERROR << "Failed to remount userdata in checkpointing mode";
+ return -1;
+ }
+ if (mount(entry->blk_device.c_str(), entry->mount_point.c_str(), "none",
+ MS_REMOUNT | entry->flags, entry->fs_options.c_str()) != 0) {
+ LERROR << "Failed to remount userdata in checkpointing mode";
+ return -1;
+ }
+ } else {
+ // TODO(b/135984674): support remounting for ext4.
+ LERROR << "Remounting in checkpointing mode is not yet supported for ext4";
+ return -1;
+ }
+ return 0;
+}
+
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index bdec7be..ca67f37 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -105,6 +105,8 @@
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);
+int fs_mgr_remount_userdata_into_checkpointing(android::fs_mgr::Fstab* fstab);
+
// Finds the dm_bow device on which this block device is stacked, or returns
// empty string
std::string fs_mgr_find_bow_device(const std::string& block_device);
diff --git a/fs_mgr/libsnapshot/dm_snapshot_internals.h b/fs_mgr/libsnapshot/dm_snapshot_internals.h
index 4903de1..fef256d 100644
--- a/fs_mgr/libsnapshot/dm_snapshot_internals.h
+++ b/fs_mgr/libsnapshot/dm_snapshot_internals.h
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+#pragma once
+
#include <stdint.h>
#include <vector>
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2f2ead0..b2c6461 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -42,6 +42,8 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <memory>
+
#include <ApexProperties.sysprop.h>
#include <android-base/chrono_utils.h>
#include <android-base/file.h>
@@ -627,6 +629,8 @@
return Error() << "Invalid code: " << code;
}
+static int initial_mount_fstab_return_code = -1;
+
/* mount_all <fstab> [ <path> ]* [--<options>]*
*
* This function might request a reboot, in which case it will
@@ -662,6 +666,7 @@
if (!ReadFstabFromFile(fstab_file, &fstab)) {
return Error() << "Could not read fstab";
}
+
auto mount_fstab_return_code = fs_mgr_mount_all(&fstab, mount_mode);
property_set(prop_name, std::to_string(t.duration().count()));
@@ -673,6 +678,7 @@
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
+ initial_mount_fstab_return_code = mount_fstab_return_code;
auto queue_fs_result = queue_fs_event(mount_fstab_return_code);
if (!queue_fs_result) {
return Error() << "queue_fs_event() failed: " << queue_fs_result.error();
@@ -1132,6 +1138,25 @@
return ExecWithFunctionOnFailure(args, reboot);
}
+static Result<void> do_remount_userdata(const BuiltinArguments& args) {
+ if (initial_mount_fstab_return_code == -1) {
+ return Error() << "Calling remount_userdata too early";
+ }
+ Fstab fstab;
+ if (!ReadDefaultFstab(&fstab)) {
+ // TODO(b/135984674): should we reboot here?
+ return Error() << "Failed to read fstab";
+ }
+ // TODO(b/135984674): check that fstab contains /data.
+ if (auto rc = fs_mgr_remount_userdata_into_checkpointing(&fstab); rc < 0) {
+ TriggerShutdown("reboot,mount-userdata-failed");
+ }
+ if (auto result = queue_fs_event(initial_mount_fstab_return_code); !result) {
+ return Error() << "queue_fs_event() failed: " << result.error();
+ }
+ return {};
+}
+
static Result<void> do_installkey(const BuiltinArguments& args) {
if (!is_file_crypto()) return {};
@@ -1243,6 +1268,7 @@
{"umount", {1, 1, {false, do_umount}}},
{"umount_all", {1, 1, {false, do_umount_all}}},
{"readahead", {1, 2, {true, do_readahead}}},
+ {"remount_userdata", {0, 0, {false, do_remount_userdata}}},
{"restart", {1, 1, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},
{"restorecon_recursive", {1, kMax, {true, do_restorecon_recursive}}},
diff --git a/init/reboot.cpp b/init/reboot.cpp
index d453655..fc18ecb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -181,10 +181,17 @@
}
}
-static void ShutdownVold() {
+static Result<void> ShutdownVold() {
const char* vdc_argv[] = {"/system/bin/vdc", "volume", "shutdown"};
int status;
- logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true, nullptr);
+ if (logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG, true,
+ nullptr) != 0) {
+ return ErrnoError() << "Failed to call 'vdc volume shutdown'";
+ }
+ if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+ return {};
+ }
+ return Error() << "'vdc volume shutdown' failed : " << status;
}
static void LogShutdownTime(UmountStat stat, Timer* t) {
@@ -427,11 +434,11 @@
#define ZRAM_DEVICE "/dev/block/zram0"
#define ZRAM_RESET "/sys/block/zram0/reset"
#define ZRAM_BACK_DEV "/sys/block/zram0/backing_dev"
-static void KillZramBackingDevice() {
+static Result<void> KillZramBackingDevice() {
std::string backing_dev;
- if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return;
+ if (!android::base::ReadFileToString(ZRAM_BACK_DEV, &backing_dev)) return {};
- if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return;
+ if (!android::base::StartsWith(backing_dev, "/dev/block/loop")) return {};
// cut the last "\n"
backing_dev.erase(backing_dev.length() - 1);
@@ -440,28 +447,29 @@
Timer swap_timer;
LOG(INFO) << "swapoff() start...";
if (swapoff(ZRAM_DEVICE) == -1) {
- LOG(ERROR) << "zram_backing_dev: swapoff (" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: swapoff (" << backing_dev << ")"
+ << " failed";
}
LOG(INFO) << "swapoff() took " << swap_timer;;
if (!WriteStringToFile("1", ZRAM_RESET)) {
- LOG(ERROR) << "zram_backing_dev: reset (" << backing_dev << ")" << " failed";
- return;
+ return Error() << "zram_backing_dev: reset (" << backing_dev << ")"
+ << " failed";
}
// clear loopback device
unique_fd loop(TEMP_FAILURE_RETRY(open(backing_dev.c_str(), O_RDWR | O_CLOEXEC)));
if (loop.get() < 0) {
- LOG(ERROR) << "zram_backing_dev: open(" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: open(" << backing_dev << ")"
+ << " failed";
}
if (ioctl(loop.get(), LOOP_CLR_FD, 0) < 0) {
- LOG(ERROR) << "zram_backing_dev: loop_clear (" << backing_dev << ")" << " failed";
- return;
+ return ErrnoError() << "zram_backing_dev: loop_clear (" << backing_dev << ")"
+ << " failed";
}
LOG(INFO) << "zram_backing_dev: `" << backing_dev << "` is cleared successfully.";
+ return {};
}
// Stops given services, waits for them to be stopped for |timeout| ms.
@@ -738,7 +746,23 @@
// TODO(b/135984674): store information about offending services for debugging.
return Error() << r << " post-data services are still running";
}
- // TODO(b/135984674): remount userdata
+ // We only really need to restart vold if userdata is ext4 filesystem.
+ // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
+ // First shutdown volumes managed by vold. They will be recreated by
+ // system_server.
+ Service* vold_service = ServiceList::GetInstance().FindService("vold");
+ if (vold_service != nullptr && vold_service->IsRunning()) {
+ if (auto result = ShutdownVold(); !result) {
+ return result;
+ }
+ LOG(INFO) << "Restarting vold";
+ vold_service->Restart();
+ }
+ // Again, we only need to kill zram backing device in case of ext4 userdata.
+ // TODO(b/135984674): get userdata fs type here, and do nothing in case of f2fs.
+ if (auto result = KillZramBackingDevice(); !result) {
+ return result;
+ }
if (int r = StopServicesAndLogViolations(GetDebuggingServices(true /* only_post_data */), 5s,
false /* SIGKILL */);
r > 0) {
diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp
index 2251479..667bddc 100644
--- a/libziparchive/Android.bp
+++ b/libziparchive/Android.bp
@@ -175,7 +175,7 @@
}
cc_binary {
- name: "unzip",
+ name: "ziptool",
defaults: ["libziparchive_flags"],
srcs: ["unzip.cpp"],
shared_libs: [
@@ -183,6 +183,12 @@
"libziparchive",
],
recovery_available: true,
+ host_supported: true,
+ target: {
+ android: {
+ symlinks: ["unzip", "zipinfo"],
+ },
+ },
}
cc_fuzz {
diff --git a/libziparchive/include/ziparchive/zip_archive.h b/libziparchive/include/ziparchive/zip_archive.h
index 391cff9..f0f5a1d 100644
--- a/libziparchive/include/ziparchive/zip_archive.h
+++ b/libziparchive/include/ziparchive/zip_archive.h
@@ -79,6 +79,12 @@
// The offset to the start of data for this ZipEntry.
off64_t offset;
+
+ // The version of zip and the host file system this came from.
+ uint16_t version_made_by;
+
+ // Whether this entry is believed to be text or binary.
+ bool is_text;
};
struct ZipArchive;
@@ -125,6 +131,19 @@
*/
void CloseArchive(ZipArchiveHandle archive);
+/** See GetArchiveInfo(). */
+struct ZipArchiveInfo {
+ /** The size in bytes of the archive itself. Used by zipinfo. */
+ off64_t archive_size;
+ /** The number of entries in the archive. */
+ size_t entry_count;
+};
+
+/**
+ * Returns information about the given archive.
+ */
+ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive);
+
/*
* Find an entry in the Zip archive, by name. |data| must be non-null.
*
diff --git a/libziparchive/unzip.cpp b/libziparchive/unzip.cpp
index 426325e..e936614 100644
--- a/libziparchive/unzip.cpp
+++ b/libziparchive/unzip.cpp
@@ -40,12 +40,15 @@
kPrompt,
};
+static bool is_unzip;
static OverwriteMode overwrite_mode = kPrompt;
+static bool flag_1 = false;
static const char* flag_d = nullptr;
static bool flag_l = false;
static bool flag_p = false;
static bool flag_q = false;
static bool flag_v = false;
+static bool flag_x = false;
static const char* archive_name = nullptr;
static std::set<std::string> includes;
static std::set<std::string> excludes;
@@ -88,32 +91,51 @@
return static_cast<int>((100LL * (uncompressed - compressed)) / uncompressed);
}
-static void MaybeShowHeader() {
- if (!flag_q) printf("Archive: %s\n", archive_name);
- if (flag_v) {
- printf(
- " Length Method Size Cmpr Date Time CRC-32 Name\n"
- "-------- ------ ------- ---- ---------- ----- -------- ----\n");
- } else if (flag_l) {
- printf(
- " Length Date Time Name\n"
- "--------- ---------- ----- ----\n");
+static void MaybeShowHeader(ZipArchiveHandle zah) {
+ if (is_unzip) {
+ // unzip has three formats.
+ if (!flag_q) printf("Archive: %s\n", archive_name);
+ if (flag_v) {
+ printf(
+ " Length Method Size Cmpr Date Time CRC-32 Name\n"
+ "-------- ------ ------- ---- ---------- ----- -------- ----\n");
+ } else if (flag_l) {
+ printf(
+ " Length Date Time Name\n"
+ "--------- ---------- ----- ----\n");
+ }
+ } else {
+ // zipinfo.
+ if (!flag_1 && includes.empty() && excludes.empty()) {
+ ZipArchiveInfo info{GetArchiveInfo(zah)};
+ printf("Archive: %s\n", archive_name);
+ printf("Zip file size: %" PRId64 " bytes, number of entries: %zu\n", info.archive_size,
+ info.entry_count);
+ }
}
}
static void MaybeShowFooter() {
- if (flag_v) {
- printf(
- "-------- ------- --- -------\n"
- "%8" PRId64 " %8" PRId64 " %3d%% %zu file%s\n",
- total_uncompressed_length, total_compressed_length,
- CompressionRatio(total_uncompressed_length, total_compressed_length), file_count,
- (file_count == 1) ? "" : "s");
- } else if (flag_l) {
- printf(
- "--------- -------\n"
- "%9" PRId64 " %zu file%s\n",
- total_uncompressed_length, file_count, (file_count == 1) ? "" : "s");
+ if (is_unzip) {
+ if (flag_v) {
+ printf(
+ "-------- ------- --- -------\n"
+ "%8" PRId64 " %8" PRId64 " %3d%% %zu file%s\n",
+ total_uncompressed_length, total_compressed_length,
+ CompressionRatio(total_uncompressed_length, total_compressed_length), file_count,
+ (file_count == 1) ? "" : "s");
+ } else if (flag_l) {
+ printf(
+ "--------- -------\n"
+ "%9" PRId64 " %zu file%s\n",
+ total_uncompressed_length, file_count, (file_count == 1) ? "" : "s");
+ }
+ } else {
+ if (!flag_1 && includes.empty() && excludes.empty()) {
+ printf("%zu files, %" PRId64 " bytes uncompressed, %" PRId64 " bytes compressed: %3d%%\n",
+ file_count, total_uncompressed_length, total_compressed_length,
+ CompressionRatio(total_uncompressed_length, total_compressed_length));
+ }
}
}
@@ -226,17 +248,61 @@
}
}
+static void InfoOne(const ZipEntry& entry, const std::string& name) {
+ if (flag_1) {
+ // "android-ndk-r19b/sources/android/NOTICE"
+ printf("%s\n", name.c_str());
+ return;
+ }
+
+ int version = entry.version_made_by & 0xff;
+ int os = (entry.version_made_by >> 8) & 0xff;
+
+ // TODO: Support suid/sgid? Non-Unix host file system attributes?
+ char mode[] = "??????????";
+ if (os == 3) {
+ mode[0] = S_ISDIR(entry.unix_mode) ? 'd' : (S_ISREG(entry.unix_mode) ? '-' : '?');
+ mode[1] = entry.unix_mode & S_IRUSR ? 'r' : '-';
+ mode[2] = entry.unix_mode & S_IWUSR ? 'w' : '-';
+ mode[3] = entry.unix_mode & S_IXUSR ? 'x' : '-';
+ mode[4] = entry.unix_mode & S_IRGRP ? 'r' : '-';
+ mode[5] = entry.unix_mode & S_IWGRP ? 'w' : '-';
+ mode[6] = entry.unix_mode & S_IXGRP ? 'x' : '-';
+ mode[7] = entry.unix_mode & S_IROTH ? 'r' : '-';
+ mode[8] = entry.unix_mode & S_IWOTH ? 'w' : '-';
+ mode[9] = entry.unix_mode & S_IXOTH ? 'x' : '-';
+ }
+
+ // TODO: zipinfo (unlike unzip) sometimes uses time zone?
+ // TODO: this uses 4-digit years because we're not barbarians unless interoperability forces it.
+ tm t = entry.GetModificationTime();
+ char time[32];
+ snprintf(time, sizeof(time), "%04d-%02d-%02d %02d:%02d", t.tm_year + 1900, t.tm_mon + 1,
+ t.tm_mday, t.tm_hour, t.tm_min);
+
+ // "-rw-r--r-- 3.0 unx 577 t- defX 19-Feb-12 16:09 android-ndk-r19b/sources/android/NOTICE"
+ printf("%s %2d.%d %s %8d %c%c %s %s %s\n", mode, version / 10, version % 10,
+ os == 3 ? "unx" : "???", entry.uncompressed_length, entry.is_text ? 't' : 'b',
+ entry.has_data_descriptor ? 'X' : 'x', entry.method == kCompressStored ? "stor" : "defX",
+ time, name.c_str());
+}
+
static void ProcessOne(ZipArchiveHandle zah, ZipEntry& entry, const std::string& name) {
- if (flag_l || flag_v) {
- // -l or -lv or -lq or -v.
- ListOne(entry, name);
- } else {
- // Actually extract.
- if (flag_p) {
- ExtractToPipe(zah, entry, name);
+ if (is_unzip) {
+ if (flag_l || flag_v) {
+ // -l or -lv or -lq or -v.
+ ListOne(entry, name);
} else {
- ExtractOne(zah, entry, name);
+ // Actually extract.
+ if (flag_p) {
+ ExtractToPipe(zah, entry, name);
+ } else {
+ ExtractOne(zah, entry, name);
+ }
}
+ } else {
+ // zipinfo or zipinfo -1.
+ InfoOne(entry, name);
}
total_uncompressed_length += entry.uncompressed_length;
total_compressed_length += entry.compressed_length;
@@ -244,7 +310,7 @@
}
static void ProcessAll(ZipArchiveHandle zah) {
- MaybeShowHeader();
+ MaybeShowHeader(zah);
// libziparchive iteration order doesn't match the central directory.
// We could sort, but that would cost extra and wouldn't match either.
@@ -267,73 +333,110 @@
}
static void ShowHelp(bool full) {
- fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
- if (!full) exit(EXIT_FAILURE);
+ if (is_unzip) {
+ fprintf(full ? stdout : stderr, "usage: unzip [-d DIR] [-lnopqv] ZIP [FILE...] [-x FILE...]\n");
+ if (!full) exit(EXIT_FAILURE);
- printf(
- "\n"
- "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
- "exclude (-x) lists use shell glob patterns.\n"
- "\n"
- "-d DIR Extract into DIR\n"
- "-l List contents (-lq excludes archive name, -lv is verbose)\n"
- "-n Never overwrite files (default: prompt)\n"
- "-o Always overwrite files\n"
- "-p Pipe to stdout\n"
- "-q Quiet\n"
- "-v List contents verbosely\n"
- "-x FILE Exclude files\n");
+ printf(
+ "\n"
+ "Extract FILEs from ZIP archive. Default is all files. Both the include and\n"
+ "exclude (-x) lists use shell glob patterns.\n"
+ "\n"
+ "-d DIR Extract into DIR\n"
+ "-l List contents (-lq excludes archive name, -lv is verbose)\n"
+ "-n Never overwrite files (default: prompt)\n"
+ "-o Always overwrite files\n"
+ "-p Pipe to stdout\n"
+ "-q Quiet\n"
+ "-v List contents verbosely\n"
+ "-x FILE Exclude files\n");
+ } else {
+ fprintf(full ? stdout : stderr, "usage: zipinfo [-1] ZIP [FILE...] [-x FILE...]\n");
+ if (!full) exit(EXIT_FAILURE);
+
+ printf(
+ "\n"
+ "Show information about FILEs from ZIP archive. Default is all files.\n"
+ "Both the include and exclude (-x) lists use shell glob patterns.\n"
+ "\n"
+ "-1 Show filenames only, one per line\n"
+ "-x FILE Exclude files\n");
+ }
exit(EXIT_SUCCESS);
}
+static void HandleCommonOption(int opt) {
+ switch (opt) {
+ case 'h':
+ ShowHelp(true);
+ break;
+ case 'x':
+ flag_x = true;
+ break;
+ case 1:
+ // -x swallows all following arguments, so we use '-' in the getopt
+ // string and collect files here.
+ if (!archive_name) {
+ archive_name = optarg;
+ } else if (flag_x) {
+ excludes.insert(optarg);
+ } else {
+ includes.insert(optarg);
+ }
+ break;
+ default:
+ ShowHelp(false);
+ break;
+ }
+}
+
int main(int argc, char* argv[]) {
static struct option opts[] = {
{"help", no_argument, 0, 'h'},
};
- bool saw_x = false;
- int opt;
- while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
- switch (opt) {
- case 'd':
- flag_d = optarg;
- break;
- case 'h':
- ShowHelp(true);
- break;
- case 'l':
- flag_l = true;
- break;
- case 'n':
- overwrite_mode = kNever;
- break;
- case 'o':
- overwrite_mode = kAlways;
- break;
- case 'p':
- flag_p = flag_q = true;
- break;
- case 'q':
- flag_q = true;
- break;
- case 'v':
- flag_v = true;
- break;
- case 'x':
- saw_x = true;
- break;
- case 1:
- // -x swallows all following arguments, so we use '-' in the getopt
- // string and collect files here.
- if (!archive_name) {
- archive_name = optarg;
- } else if (saw_x) {
- excludes.insert(optarg);
- } else {
- includes.insert(optarg);
- }
- break;
- default:
- ShowHelp(false);
+
+ is_unzip = !strcmp(basename(argv[0]), "unzip");
+ if (is_unzip) {
+ int opt;
+ while ((opt = getopt_long(argc, argv, "-d:hlnopqvx", opts, nullptr)) != -1) {
+ switch (opt) {
+ case 'd':
+ flag_d = optarg;
+ break;
+ case 'l':
+ flag_l = true;
+ break;
+ case 'n':
+ overwrite_mode = kNever;
+ break;
+ case 'o':
+ overwrite_mode = kAlways;
+ break;
+ case 'p':
+ flag_p = flag_q = true;
+ break;
+ case 'q':
+ flag_q = true;
+ break;
+ case 'v':
+ flag_v = true;
+ break;
+ default:
+ HandleCommonOption(opt);
+ break;
+ }
+ }
+ } else {
+ int opt;
+ while ((opt = getopt_long(argc, argv, "-1hx", opts, nullptr)) != -1) {
+ switch (opt) {
+ case '1':
+ flag_1 = true;
+ break;
+ default:
+ HandleCommonOption(opt);
+ break;
+ }
}
}
diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc
index 3a552d8..caf8fae 100644
--- a/libziparchive/zip_archive.cc
+++ b/libziparchive/zip_archive.cc
@@ -478,6 +478,13 @@
return OpenArchiveInternal(archive, debug_file_name);
}
+ZipArchiveInfo GetArchiveInfo(ZipArchiveHandle archive) {
+ ZipArchiveInfo result;
+ result.archive_size = archive->mapped_zip.GetFileLength();
+ result.entry_count = archive->num_entries;
+ return result;
+}
+
/*
* Close a ZipArchive, closing the file and freeing the contents.
*/
@@ -614,12 +621,17 @@
}
// 4.4.2.1: the upper byte of `version_made_by` gives the source OS. Unix is 3.
- if ((cdr->version_made_by >> 8) == 3) {
+ data->version_made_by = cdr->version_made_by;
+ if ((data->version_made_by >> 8) == 3) {
data->unix_mode = (cdr->external_file_attributes >> 16) & 0xffff;
} else {
data->unix_mode = 0777;
}
+ // 4.4.14: the lowest bit of the internal file attributes field indicates text.
+ // Currently only needed to implement zipinfo.
+ data->is_text = (cdr->internal_file_attributes & 1);
+
// Check that the local file header name matches the declared
// name in the central directory.
if (lfh->file_name_length != nameLen) {
diff --git a/logcat/Android.bp b/logcat/Android.bp
index e6b0c7d..e472d08 100644
--- a/logcat/Android.bp
+++ b/logcat/Android.bp
@@ -21,6 +21,7 @@
"-Wall",
"-Wextra",
"-Werror",
+ "-DANDROID_BASE_UNIQUE_FD_DISABLE_IMPLICIT_CONVERSION=1",
],
shared_libs: [
"libbase",
diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp
index f164a12..1517c33 100644
--- a/logcat/logcat.cpp
+++ b/logcat/logcat.cpp
@@ -16,16 +16,12 @@
#include "logcat.h"
-#include <android-base/macros.h>
-#include <arpa/inet.h>
-#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <math.h>
-#include <pthread.h>
#include <sched.h>
#include <stdarg.h>
#include <stdio.h>
@@ -34,13 +30,11 @@
#include <sys/cdefs.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
-#include <atomic>
#include <memory>
#include <regex>
#include <string>
@@ -48,10 +42,11 @@
#include <vector>
#include <android-base/file.h>
+#include <android-base/macros.h>
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
-#include <cutils/sockets.h>
+#include <android-base/unique_fd.h>
#include <log/event_tag_map.h>
#include <log/logprint.h>
#include <private/android_logger.h>
@@ -60,6 +55,8 @@
#define DEFAULT_MAX_ROTATED_LOGS 4
+using android::base::StringPrintf;
+
struct log_device_t {
const char* device;
bool binary;
@@ -79,85 +76,51 @@
}
};
-struct android_logcat_context_internal {
- // status
- volatile std::atomic_int retval; // valid if thread_stopped set
- // Arguments passed in, or copies and storage thereof if a thread.
- int argc;
- char* const* argv;
- char* const* envp;
- std::vector<std::string> args;
- std::vector<const char*> argv_hold;
- std::vector<std::string> envs;
- std::vector<const char*> envp_hold;
- int output_fd; // duplication of fileno(output) (below)
- int error_fd; // duplication of fileno(error) (below)
+class Logcat {
+ public:
+ ~Logcat();
- // library
- int fds[2]; // From popen call
- FILE* output; // everything writes to fileno(output), buffer unused
- FILE* error; // unless error == output.
- pthread_t thr;
- volatile std::atomic_bool stop; // quick exit flag
- volatile std::atomic_bool thread_stopped;
- bool stderr_null; // shell "2>/dev/null"
- bool stderr_stdout; // shell "2>&1"
+ int Run(int argc, char** argv);
- // global variables
- AndroidLogFormat* logformat;
- const char* outputFileName;
+ private:
+ void RotateLogs();
+ void ProcessBuffer(log_device_t* dev, struct log_msg* buf);
+ void MaybePrintStart(log_device_t* dev, bool print_dividers);
+ void SetupOutputAndSchedulingPolicy(bool blocking);
+ int SetLogFormat(const char* format_string);
+
+ android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
+ std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
+ android_log_format_new(), &android_log_format_free};
+ const char* output_file_name_ = nullptr;
// 0 means "no log rotation"
- size_t logRotateSizeKBytes;
+ size_t log_rotate_size_kb_ = 0;
// 0 means "unbounded"
- size_t maxRotatedLogs;
- size_t outByteCount;
- int printBinary;
- int devCount; // >1 means multiple
- std::unique_ptr<std::regex> regex;
- log_device_t* devices;
- EventTagMap* eventTagMap;
+ size_t max_rotated_logs_ = DEFAULT_MAX_ROTATED_LOGS;
+ size_t out_byte_count_ = 0;
+ int print_binary_ = 0;
+ int dev_count_ = 0; // >1 means multiple
+ std::unique_ptr<std::regex> regex_;
+ log_device_t* devices_ = nullptr;
+ std::unique_ptr<EventTagMap, decltype(&android_closeEventTagMap)> event_tag_map_{
+ nullptr, &android_closeEventTagMap};
// 0 means "infinite"
- size_t maxCount;
- size_t printCount;
+ size_t max_count_ = 0;
+ size_t print_count_ = 0;
- bool printItAnyways;
- bool debug;
- bool hasOpenedEventTagMap;
+ bool print_it_anyways_ = false;
+ bool debug_ = false;
+ bool has_opened_event_tag_map_ = false;
};
-// Creates a context associated with this logcat instance
-android_logcat_context create_android_logcat() {
- android_logcat_context_internal* context;
-
- context = (android_logcat_context_internal*)calloc(
- 1, sizeof(android_logcat_context_internal));
- if (!context) return nullptr;
-
- context->fds[0] = -1;
- context->fds[1] = -1;
- context->output_fd = -1;
- context->error_fd = -1;
- context->maxRotatedLogs = DEFAULT_MAX_ROTATED_LOGS;
-
- context->argv_hold.clear();
- context->args.clear();
- context->envp_hold.clear();
- context->envs.clear();
-
- return (android_logcat_context)context;
-}
-
// logd prefixes records with a length field
#define RECORD_LENGTH_FIELD_SIZE_BYTES sizeof(uint32_t)
-namespace android {
-
enum helpType { HELP_FALSE, HELP_TRUE, HELP_FORMAT };
-// if showHelp is set, newline required in fmt statement to transition to usage
-static void logcat_panic(android_logcat_context_internal* context,
- enum helpType showHelp, const char* fmt, ...)
- __printflike(3, 4);
+// if show_help is set, newline required in fmt statement to transition to usage
+static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) __printflike(2, 3)
+ __attribute__((__noreturn__));
#ifndef F2FS_IOC_SET_PIN_FILE
#define F2FS_IOCTL_MAGIC 0xf5
@@ -165,7 +128,7 @@
#endif
static int openLogFile(const char* pathname, size_t sizeKB) {
- int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
+ int fd = open(pathname, O_WRONLY | O_APPEND | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
if (fd < 0) {
return fd;
}
@@ -177,107 +140,29 @@
return fd;
}
-static void close_output(android_logcat_context_internal* context) {
- // split output_from_error
- if (context->error == context->output) {
- context->output = nullptr;
- context->output_fd = -1;
- }
- if (context->error && (context->output_fd == fileno(context->error))) {
- context->output_fd = -1;
- }
- if (context->output_fd == context->error_fd) {
- context->output_fd = -1;
- }
- // close output channel
- if (context->output) {
- if (context->output != stdout) {
- if (context->output_fd == fileno(context->output)) {
- context->output_fd = -1;
- }
- if (context->fds[1] == fileno(context->output)) {
- context->fds[1] = -1;
- }
- fclose(context->output);
- }
- context->output = nullptr;
- }
- if (context->output_fd >= 0) {
- if (context->output_fd != fileno(stdout)) {
- if (context->fds[1] == context->output_fd) {
- context->fds[1] = -1;
- }
- posix_fadvise(context->output_fd, 0, 0, POSIX_FADV_DONTNEED);
- close(context->output_fd);
- }
- context->output_fd = -1;
- }
-}
-
-static void close_error(android_logcat_context_internal* context) {
- // split error_from_output
- if (context->output == context->error) {
- context->error = nullptr;
- context->error_fd = -1;
- }
- if (context->output && (context->error_fd == fileno(context->output))) {
- context->error_fd = -1;
- }
- if (context->error_fd == context->output_fd) {
- context->error_fd = -1;
- }
- // close error channel
- if (context->error) {
- if ((context->error != stderr) && (context->error != stdout)) {
- if (context->error_fd == fileno(context->error)) {
- context->error_fd = -1;
- }
- if (context->fds[1] == fileno(context->error)) {
- context->fds[1] = -1;
- }
- fclose(context->error);
- }
- context->error = nullptr;
- }
- if (context->error_fd >= 0) {
- if ((context->error_fd != fileno(stdout)) &&
- (context->error_fd != fileno(stderr))) {
- if (context->fds[1] == context->error_fd) context->fds[1] = -1;
- close(context->error_fd);
- }
- context->error_fd = -1;
- }
-}
-
-static void rotateLogs(android_logcat_context_internal* context) {
- int err;
-
+void Logcat::RotateLogs() {
// Can't rotate logs if we're not outputting to a file
- if (!context->outputFileName) return;
+ if (!output_file_name_) return;
- close_output(context);
+ output_fd_.reset();
// Compute the maximum number of digits needed to count up to
// maxRotatedLogs in decimal. eg:
// maxRotatedLogs == 30
// -> log10(30) == 1.477
// -> maxRotationCountDigits == 2
- int maxRotationCountDigits =
- (context->maxRotatedLogs > 0)
- ? (int)(floor(log10(context->maxRotatedLogs) + 1))
- : 0;
+ int max_rotation_count_digits =
+ max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
- for (int i = context->maxRotatedLogs; i > 0; i--) {
- std::string file1 = android::base::StringPrintf(
- "%s.%.*d", context->outputFileName, maxRotationCountDigits, i);
+ for (int i = max_rotated_logs_; i > 0; i--) {
+ std::string file1 =
+ StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i);
std::string file0;
if (!(i - 1)) {
- file0 = android::base::StringPrintf("%s", context->outputFileName);
+ file0 = output_file_name_;
} else {
- file0 =
- android::base::StringPrintf("%s.%.*d", context->outputFileName,
- maxRotationCountDigits, i - 1);
+ file0 = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits, i - 1);
}
if (!file0.length() || !file1.length()) {
@@ -285,169 +170,123 @@
break;
}
- err = rename(file0.c_str(), file1.c_str());
+ int err = rename(file0.c_str(), file1.c_str());
if (err < 0 && errno != ENOENT) {
perror("while rotating log files");
}
}
- context->output_fd = openLogFile(context->outputFileName, context->logRotateSizeKBytes);
+ output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
- if (context->output_fd < 0) {
- logcat_panic(context, HELP_FALSE, "couldn't open output file");
- return;
- }
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- logcat_panic(context, HELP_FALSE, "couldn't fdopen output file");
- return;
- }
- if (context->stderr_stdout) {
- close_error(context);
- context->error = context->output;
- context->error_fd = context->output_fd;
+ if (!output_fd_.ok()) {
+ LogcatPanic(HELP_FALSE, "couldn't open output file");
}
- context->outByteCount = 0;
+ out_byte_count_ = 0;
}
-void printBinary(android_logcat_context_internal* context, struct log_msg* buf) {
- size_t size = buf->len();
-
- TEMP_FAILURE_RETRY(write(context->output_fd, buf, size));
-}
-
-static bool regexOk(android_logcat_context_internal* context,
- const AndroidLogEntry& entry) {
- if (!context->regex) return true;
-
- return std::regex_search(entry.message, entry.message + entry.messageLen, *context->regex);
-}
-
-static void processBuffer(android_logcat_context_internal* context,
- log_device_t* dev, struct log_msg* buf) {
+void Logcat::ProcessBuffer(log_device_t* dev, struct log_msg* buf) {
int bytesWritten = 0;
int err;
AndroidLogEntry entry;
char binaryMsgBuf[1024];
if (dev->binary) {
- if (!context->eventTagMap && !context->hasOpenedEventTagMap) {
- context->eventTagMap = android_openEventTagMap(nullptr);
- context->hasOpenedEventTagMap = true;
+ if (!event_tag_map_ && !has_opened_event_tag_map_) {
+ event_tag_map_.reset(android_openEventTagMap(nullptr));
+ has_opened_event_tag_map_ = true;
}
- err = android_log_processBinaryLogBuffer(&buf->entry, &entry, context->eventTagMap,
+ err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
binaryMsgBuf, sizeof(binaryMsgBuf));
// printf(">>> pri=%d len=%d msg='%s'\n",
// entry.priority, entry.messageLen, entry.message);
} else {
err = android_log_processLogBuffer(&buf->entry, &entry);
}
- if ((err < 0) && !context->debug) return;
+ if (err < 0 && !debug_) return;
- if (android_log_shouldPrintLine(
- context->logformat, std::string(entry.tag, entry.tagLen).c_str(),
- entry.priority)) {
- bool match = regexOk(context, entry);
+ if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
+ entry.priority)) {
+ bool match = !regex_ ||
+ std::regex_search(entry.message, entry.message + entry.messageLen, *regex_);
- context->printCount += match;
- if (match || context->printItAnyways) {
- bytesWritten = android_log_printLogLine(context->logformat,
- context->output_fd, &entry);
+ print_count_ += match;
+ if (match || print_it_anyways_) {
+ bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);
if (bytesWritten < 0) {
- logcat_panic(context, HELP_FALSE, "output error");
- return;
+ LogcatPanic(HELP_FALSE, "output error");
}
}
}
- context->outByteCount += bytesWritten;
+ out_byte_count_ += bytesWritten;
- if (context->logRotateSizeKBytes > 0 &&
- (context->outByteCount / 1024) >= context->logRotateSizeKBytes) {
- rotateLogs(context);
+ if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
+ RotateLogs();
}
}
-static void maybePrintStart(android_logcat_context_internal* context,
- log_device_t* dev, bool printDividers) {
- if (!dev->printed || printDividers) {
- if (context->devCount > 1 && !context->printBinary) {
- char buf[1024];
- snprintf(buf, sizeof(buf), "--------- %s %s\n",
- dev->printed ? "switch to" : "beginning of", dev->device);
- if (write(context->output_fd, buf, strlen(buf)) < 0) {
- logcat_panic(context, HELP_FALSE, "output error");
- return;
+void Logcat::MaybePrintStart(log_device_t* dev, bool print_dividers) {
+ if (!dev->printed || print_dividers) {
+ if (dev_count_ > 1 && !print_binary_) {
+ if (dprintf(output_fd_.get(), "--------- %s %s\n",
+ dev->printed ? "switch to" : "beginning of", dev->device) < 0) {
+ LogcatPanic(HELP_FALSE, "output error");
}
}
dev->printed = true;
}
}
-static void setupOutputAndSchedulingPolicy(
- android_logcat_context_internal* context, bool blocking) {
- if (!context->outputFileName) return;
+void Logcat::SetupOutputAndSchedulingPolicy(bool blocking) {
+ if (!output_file_name_) return;
if (blocking) {
// Lower priority and set to batch scheduling if we are saving
// the logs into files and taking continuous content.
- if ((set_sched_policy(0, SP_BACKGROUND) < 0) && context->error) {
- fprintf(context->error,
- "failed to set background scheduling policy\n");
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+ fprintf(stderr, "failed to set background scheduling policy\n");
}
- struct sched_param param;
- memset(¶m, 0, sizeof(param));
+ struct sched_param param = {};
if (sched_setscheduler((pid_t)0, SCHED_BATCH, ¶m) < 0) {
fprintf(stderr, "failed to set to batch scheduler\n");
}
- if ((setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) &&
- context->error) {
- fprintf(context->error, "failed set to priority\n");
+ if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
+ fprintf(stderr, "failed set to priority\n");
}
}
- close_output(context);
+ output_fd_.reset(openLogFile(output_file_name_, log_rotate_size_kb_));
- context->output_fd = openLogFile(context->outputFileName, context->logRotateSizeKBytes);
-
- if (context->output_fd < 0) {
- logcat_panic(context, HELP_FALSE, "couldn't open output file");
- return;
+ if (!output_fd_.ok()) {
+ LogcatPanic(HELP_FALSE, "couldn't open output file");
}
struct stat statbuf;
- if (fstat(context->output_fd, &statbuf) == -1) {
- close_output(context);
- logcat_panic(context, HELP_FALSE, "couldn't get output file stat\n");
- return;
+ if (fstat(output_fd_.get(), &statbuf) == -1) {
+ output_fd_.reset();
+ LogcatPanic(HELP_FALSE, "couldn't get output file stat\n");
}
if ((size_t)statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
- close_output(context);
- logcat_panic(context, HELP_FALSE, "invalid output file stat\n");
- return;
+ output_fd_.reset();
+ LogcatPanic(HELP_FALSE, "invalid output file stat\n");
}
- context->output = fdopen(context->output_fd, "web");
-
- context->outByteCount = statbuf.st_size;
+ out_byte_count_ = statbuf.st_size;
}
// clang-format off
-static void show_help(android_logcat_context_internal* context) {
- if (!context->error) return;
+static void show_help() {
+ const char* cmd = getprogname();
- const char* cmd = strrchr(context->argv[0], '/');
- cmd = cmd ? cmd + 1 : context->argv[0];
+ fprintf(stderr, "Usage: %s [options] [filterspecs]\n", cmd);
- fprintf(context->error, "Usage: %s [options] [filterspecs]\n", cmd);
-
- fprintf(context->error, "options include:\n"
+ fprintf(stderr, "options include:\n"
" -s Set default filter to silent. Equivalent to filterspec '*:S'\n"
" -f <file>, --file=<file> Log to file. Default is stdout\n"
" -r <kbytes>, --rotate-kbytes=<kbytes>\n"
@@ -514,7 +353,7 @@
" comes first. Improves efficiency of polling by providing\n"
" an about-to-wrap wakeup.\n");
- fprintf(context->error, "\nfilterspecs are a series of \n"
+ fprintf(stderr, "\nfilterspecs are a series of \n"
" <tag>[:priority]\n\n"
"where <tag> is a log component tag (or * for all) and priority is:\n"
" V Verbose (default for <tag>)\n"
@@ -532,9 +371,8 @@
"or defaults to \"threadtime\"\n\n");
}
-static void show_format_help(android_logcat_context_internal* context) {
- if (!context->error) return;
- fprintf(context->error,
+static void show_format_help() {
+ fprintf(stderr,
"-v <format>, --format=<format> options:\n"
" Sets log print format verb and adverbs, where <format> is:\n"
" brief long process raw tag thread threadtime time\n"
@@ -568,16 +406,13 @@
}
// clang-format on
-static int setLogFormat(android_logcat_context_internal* context,
- const char* formatString) {
- AndroidLogPrintFormat format;
-
- format = android_log_formatFromString(formatString);
+int Logcat::SetLogFormat(const char* format_string) {
+ AndroidLogPrintFormat format = android_log_formatFromString(format_string);
// invalid string?
if (format == FORMAT_OFF) return -1;
- return android_log_setPrintFormat(context->logformat, format);
+ return android_log_setPrintFormat(logformat_.get(), format);
}
static std::pair<unsigned long, const char*> format_of_size(unsigned long value) {
@@ -607,32 +442,25 @@
return true;
}
-static void logcat_panic(android_logcat_context_internal* context,
- enum helpType showHelp, const char* fmt, ...) {
- context->retval = EXIT_FAILURE;
- if (!context->error) {
- context->stop = true;
- return;
- }
-
+static void LogcatPanic(enum helpType showHelp, const char* fmt, ...) {
va_list args;
va_start(args, fmt);
- vfprintf(context->error, fmt, args);
+ vfprintf(stderr, fmt, args);
va_end(args);
switch (showHelp) {
case HELP_TRUE:
- show_help(context);
+ show_help();
break;
case HELP_FORMAT:
- show_format_help(context);
+ show_format_help();
break;
case HELP_FALSE:
default:
break;
}
- context->stop = true;
+ exit(EXIT_FAILURE);
}
static char* parseTime(log_time& t, const char* cp) {
@@ -712,18 +540,6 @@
return retval;
}
-const char* getenv(android_logcat_context_internal* context, const char* name) {
- if (!context->envp || !name || !*name) return nullptr;
-
- for (size_t len = strlen(name), i = 0; context->envp[i]; ++i) {
- if (strncmp(context->envp[i], name, len)) continue;
- if (context->envp[i][len] == '=') return &context->envp[i][len + 1];
- }
- return nullptr;
-}
-
-} // namespace android
-
void reportErrorName(const char** current, const char* name,
bool blockSecurity) {
if (*current) return;
@@ -732,8 +548,7 @@
}
}
-static int __logcat(android_logcat_context_internal* context) {
- using namespace android;
+int Logcat::Run(int argc, char** argv) {
int err;
bool hasSetLogFormat = false;
bool clearLog = false;
@@ -760,101 +575,10 @@
const char* clearFail = nullptr;
const char* setSizeFail = nullptr;
const char* getSizeFail = nullptr;
- int argc = context->argc;
- char* const* argv = context->argv;
-
- context->output = stdout;
- context->error = stderr;
-
- for (int i = 0; i < argc; ++i) {
- // Simulate shell stderr redirect parsing
- if ((argv[i][0] != '2') || (argv[i][1] != '>')) continue;
-
- // Append to file not implemented, just open file
- size_t skip = (argv[i][2] == '>') + 2;
- if (!strcmp(&argv[i][skip], "/dev/null")) {
- context->stderr_null = true;
- } else if (!strcmp(&argv[i][skip], "&1")) {
- context->stderr_stdout = true;
- } else {
- // stderr file redirections are not supported
- fprintf(context->stderr_stdout ? stdout : stderr,
- "stderr redirection to file %s unsupported, skipping\n",
- &argv[i][skip]);
- }
- // Only the first one
- break;
- }
-
- const char* filename = nullptr;
- for (int i = 0; i < argc; ++i) {
- // Simulate shell stdout redirect parsing
- if (argv[i][0] != '>') continue;
-
- // Append to file not implemented, just open file
- filename = &argv[i][(argv[i][1] == '>') + 1];
- // Only the first one
- break;
- }
-
- // Deal with setting up file descriptors and FILE pointers
- if (context->error_fd >= 0) { // Is an error file descriptor supplied?
- if (context->error_fd == context->output_fd) {
- context->stderr_stdout = true;
- } else if (context->stderr_null) { // redirection told us to close it
- close(context->error_fd);
- context->error_fd = -1;
- } else { // All Ok, convert error to a FILE pointer
- context->error = fdopen(context->error_fd, "web");
- if (!context->error) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : stderr,
- "Failed to fdopen(error_fd=%d) %s\n", context->error_fd,
- strerror(errno));
- goto exit;
- }
- }
- }
- if (context->output_fd >= 0) { // Is an output file descriptor supplied?
- if (filename) { // redirect to file, close supplied file descriptor.
- close(context->output_fd);
- context->output_fd = -1;
- } else { // All Ok, convert output to a FILE pointer
- context->output = fdopen(context->output_fd, "web");
- if (!context->output) {
- context->retval = -errno;
- fprintf(context->stderr_stdout ? stdout : context->error,
- "Failed to fdopen(output_fd=%d) %s\n",
- context->output_fd, strerror(errno));
- goto exit;
- }
- }
- }
- if (filename) { // We supplied an output file redirected in command line
- context->output = fopen(filename, "web");
- }
- // Deal with 2>&1
- if (context->stderr_stdout) context->error = context->output;
- // Deal with 2>/dev/null
- if (context->stderr_null) {
- context->error_fd = -1;
- context->error = nullptr;
- }
- // Only happens if output=stdout or output=filename
- if ((context->output_fd < 0) && context->output) {
- context->output_fd = fileno(context->output);
- }
- // Only happens if error=stdout || error=stderr
- if ((context->error_fd < 0) && context->error) {
- context->error_fd = fileno(context->error);
- }
-
- context->logformat = android_log_format_new();
if (argc == 2 && !strcmp(argv[1], "--help")) {
- show_help(context);
- context->retval = EXIT_SUCCESS;
- goto exit;
+ show_help();
+ return EXIT_SUCCESS;
}
// meant to catch comma-delimited values, but cast a wider
@@ -912,15 +636,13 @@
// only long options
if (long_options[option_index].name == pid_str) {
if (pid != 0) {
- logcat_panic(context, HELP_TRUE, "Only supports one PID argument.\n");
- goto exit;
+ LogcatPanic(HELP_TRUE, "Only supports one PID argument.\n");
}
// ToDo: determine runtime PID_MAX?
if (!getSizeTArg(optarg, &pid, 1)) {
- logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name, optarg);
}
break;
}
@@ -930,25 +652,22 @@
// ToDo: implement API that supports setting a wrap timeout
size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT;
if (optarg && !getSizeTArg(optarg, &dummy, 1)) {
- logcat_panic(context, HELP_TRUE, "%s %s out of range\n",
- long_options[option_index].name, optarg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "%s %s out of range\n",
+ long_options[option_index].name, optarg);
}
- if ((dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) &&
- context->error) {
- fprintf(context->error,
- "WARNING: %s %u seconds, ignoring %zu\n",
- long_options[option_index].name,
- ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, dummy);
+ if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) {
+ fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n",
+ long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT,
+ dummy);
}
break;
}
if (long_options[option_index].name == print_str) {
- context->printItAnyways = true;
+ print_it_anyways_ = true;
break;
}
if (long_options[option_index].name == debug_str) {
- context->debug = true;
+ debug_ = true;
break;
}
if (long_options[option_index].name == id_str) {
@@ -958,7 +677,7 @@
case 's':
// default to all silent
- android_log_addFilterRule(context->logformat, "*:s");
+ android_log_addFilterRule(logformat_.get(), "*:s");
break;
case 'c':
@@ -983,25 +702,18 @@
if (strspn(optarg, "0123456789") != strlen(optarg)) {
char* cp = parseTime(tail_time, optarg);
if (!cp) {
- logcat_panic(context, HELP_FALSE, "-%c \"%s\" not in time format\n", c,
- optarg);
- goto exit;
+ LogcatPanic(HELP_FALSE, "-%c \"%s\" not in time format\n", c, optarg);
}
if (*cp) {
char ch = *cp;
*cp = '\0';
- if (context->error) {
- fprintf(context->error, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n",
- c, optarg, ch, cp + 1);
- }
+ fprintf(stderr, "WARNING: -%c \"%s\"\"%c%s\" time truncated\n", c, optarg,
+ ch, cp + 1);
*cp = ch;
}
} else {
if (!getSizeTArg(optarg, &tail_lines, 1)) {
- if (context->error) {
- fprintf(context->error, "WARNING: -%c %s invalid, setting to 1\n", c,
- optarg);
- }
+ fprintf(stderr, "WARNING: -%c %s invalid, setting to 1\n", c, optarg);
tail_lines = 1;
}
}
@@ -1012,14 +724,13 @@
break;
case 'e':
- context->regex.reset(new std::regex(optarg));
+ regex_.reset(new std::regex(optarg));
break;
case 'm': {
- if (!getSizeTArg(optarg, &context->maxCount)) {
- logcat_panic(context, HELP_FALSE,
- "-%c \"%s\" isn't an integer greater than zero\n", c, optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &max_count_)) {
+ LogcatPanic(HELP_FALSE, "-%c \"%s\" isn't an integer greater than zero\n", c,
+ optarg);
}
} break;
@@ -1059,9 +770,7 @@
}
if (!setLogSize) {
- logcat_panic(context, HELP_FALSE,
- "ERROR: -G <num><multiplier>\n");
- goto exit;
+ LogcatPanic(HELP_FALSE, "ERROR: -G <num><multiplier>\n");
}
} break;
@@ -1093,9 +802,7 @@
const char* name = android_log_id_to_name(log_id);
if (!!strcmp(name, arg)) {
- logcat_panic(context, HELP_TRUE,
- "unknown buffer %s\n", arg);
- goto exit;
+ LogcatPanic(HELP_TRUE, "unknown buffer %s\n", arg);
}
if (log_id == LOG_ID_SECURITY) allSelected = false;
idMask |= (1 << log_id);
@@ -1111,7 +818,7 @@
if (!(idMask & (1 << i))) continue;
bool found = false;
- for (dev = context->devices; dev; dev = dev->next) {
+ for (dev = devices_; dev; dev = dev->next) {
if (!strcmp(name, dev->device)) {
found = true;
break;
@@ -1129,14 +836,14 @@
dev->next = d;
dev = d;
} else {
- context->devices = dev = d;
+ devices_ = dev = d;
}
- context->devCount++;
+ dev_count_++;
}
} break;
case 'B':
- context->printBinary = 1;
+ print_binary_ = 1;
break;
case 'f':
@@ -1144,38 +851,33 @@
tail_time = lastLogTime(optarg);
}
// redirect output to a file
- context->outputFileName = optarg;
+ output_file_name_ = optarg;
break;
case 'r':
- if (!getSizeTArg(optarg, &context->logRotateSizeKBytes, 1)) {
- logcat_panic(context, HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &log_rotate_size_kb_, 1)) {
+ LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -r\n", optarg);
}
break;
case 'n':
- if (!getSizeTArg(optarg, &context->maxRotatedLogs, 1)) {
- logcat_panic(context, HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
- goto exit;
+ if (!getSizeTArg(optarg, &max_rotated_logs_, 1)) {
+ LogcatPanic(HELP_TRUE, "Invalid parameter \"%s\" to -n\n", optarg);
}
break;
case 'v': {
if (!strcmp(optarg, "help") || !strcmp(optarg, "--help")) {
- show_format_help(context);
- context->retval = EXIT_SUCCESS;
- goto exit;
+ show_format_help();
+ return EXIT_SUCCESS;
}
std::unique_ptr<char, void (*)(void*)> formats(strdup(optarg), free);
char* arg = formats.get();
char* sv = nullptr; // protect against -ENOMEM above
while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = setLogFormat(context, arg);
+ err = SetLogFormat(arg);
if (err < 0) {
- logcat_panic(context, HELP_FORMAT,
- "Invalid parameter \"%s\" to -v\n", arg);
- goto exit;
+ LogcatPanic(HELP_FORMAT, "Invalid parameter \"%s\" to -v\n", arg);
}
arg = nullptr;
if (err) hasSetLogFormat = true;
@@ -1198,8 +900,7 @@
{
// if not in emulator, exit quietly
if (false == android::base::GetBoolProperty(QEMU_PROPERTY, false)) {
- context->retval = EXIT_SUCCESS;
- goto exit;
+ return EXIT_SUCCESS;
}
std::string cmdline = android::base::GetProperty(QEMU_CMDLINE, "");
@@ -1210,8 +911,7 @@
const char* logcatFilter = strstr(cmdline.c_str(), LOGCAT_FILTER);
// if nothing found or invalid filters, exit quietly
if (!logcatFilter) {
- context->retval = EXIT_SUCCESS;
- goto exit;
+ return EXIT_SUCCESS;
}
const char* p = logcatFilter + strlen(LOGCAT_FILTER);
@@ -1230,8 +930,7 @@
} else if (console) {
p = console + strlen(CONSOLE_OPTION);
} else {
- context->retval = EXIT_FAILURE;
- goto exit;
+ return EXIT_FAILURE;
}
q = strpbrk(p, " \t\n\r");
@@ -1248,37 +947,26 @@
devname = devname.substr(0, pos);
}
}
- cmdline.erase();
- if (context->error) {
- fprintf(context->error, "logcat using %s\n",
- devname.c_str());
+ fprintf(stderr, "logcat using %s\n", devname.c_str());
+
+ int fd = open(devname.c_str(), O_WRONLY | O_CLOEXEC);
+ if (fd < 0) {
+ break;
}
- FILE* fp = fopen(devname.c_str(), "web");
- devname.erase();
- if (!fp) break;
-
if (consolePipe) {
// need the trailing '\0'
- if(!android::base::WriteFully(fileno(fp), pipePurpose.c_str(),
- pipePurpose.size() + 1)) {
- fclose(fp);
- context->retval = EXIT_FAILURE;
- goto exit;
+ if (!android::base::WriteFully(fd, pipePurpose.c_str(),
+ pipePurpose.size() + 1)) {
+ close(fd);
+ return EXIT_FAILURE;
}
}
-
// close output and error channels, replace with console
- android::close_output(context);
- android::close_error(context);
- context->stderr_stdout = true;
- context->output = fp;
- context->output_fd = fileno(fp);
- if (context->stderr_null) break;
- context->stderr_stdout = true;
- context->error = fp;
- context->error_fd = fileno(fp);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ close(fd);
}
break;
@@ -1287,69 +975,59 @@
break;
case ':':
- logcat_panic(context, HELP_TRUE, "Option -%c needs an argument\n", optopt);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Option -%c needs an argument\n", optopt);
case 'h':
- show_help(context);
- show_format_help(context);
- goto exit;
+ show_help();
+ show_format_help();
+ return EXIT_SUCCESS;
default:
- logcat_panic(context, HELP_TRUE, "Unrecognized Option %c\n", optopt);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Unrecognized Option %c\n", optopt);
}
}
- if (context->maxCount && got_t) {
- logcat_panic(context, HELP_TRUE,
- "Cannot use -m (--max-count) and -t together\n");
- goto exit;
+ if (max_count_ && got_t) {
+ LogcatPanic(HELP_TRUE, "Cannot use -m (--max-count) and -t together\n");
}
- if (context->printItAnyways && (!context->regex || !context->maxCount)) {
+ if (print_it_anyways_ && (!regex_ || !max_count_)) {
// One day it would be nice if --print -v color and --regex <expr>
// could play with each other and show regex highlighted content.
- // clang-format off
- if (context->error) {
- fprintf(context->error, "WARNING: "
- "--print ignored, to be used in combination with\n"
- " "
- "--regex <expr> and --max-count <N>\n");
- }
- context->printItAnyways = false;
+ fprintf(stderr,
+ "WARNING: "
+ "--print ignored, to be used in combination with\n"
+ " "
+ "--regex <expr> and --max-count <N>\n");
+ print_it_anyways_ = false;
}
- if (!context->devices) {
- dev = context->devices = new log_device_t("main", false);
- context->devCount = 1;
+ if (!devices_) {
+ dev = devices_ = new log_device_t("main", false);
+ dev_count_ = 1;
if (android_name_to_log_id("system") == LOG_ID_SYSTEM) {
dev = dev->next = new log_device_t("system", false);
- context->devCount++;
+ dev_count_++;
}
if (android_name_to_log_id("crash") == LOG_ID_CRASH) {
dev = dev->next = new log_device_t("crash", false);
- context->devCount++;
+ dev_count_++;
}
if (android_name_to_log_id("kernel") == LOG_ID_KERNEL) {
dev = dev->next = new log_device_t("kernel", false);
- context->devCount++;
+ dev_count_++;
}
}
- if (!!context->logRotateSizeKBytes && !context->outputFileName) {
- logcat_panic(context, HELP_TRUE, "-r requires -f as well\n");
- goto exit;
+ if (log_rotate_size_kb_ != 0 && !output_file_name_) {
+ LogcatPanic(HELP_TRUE, "-r requires -f as well\n");
}
- if (!!setId) {
- if (!context->outputFileName) {
- logcat_panic(context, HELP_TRUE,
- "--id='%s' requires -f as well\n", setId);
- goto exit;
+ if (setId != 0) {
+ if (!output_file_name_) {
+ LogcatPanic(HELP_TRUE, "--id='%s' requires -f as well\n", setId);
}
- std::string file_name = android::base::StringPrintf(
- "%s.id", context->outputFileName);
+ std::string file_name = StringPrintf("%s.id", output_file_name_);
std::string file;
bool file_ok = android::base::ReadFileToString(file_name, &file);
android::base::WriteStringToFile(setId, file_name, S_IRUSR | S_IWUSR,
@@ -1358,7 +1036,7 @@
}
if (!hasSetLogFormat) {
- const char* logFormat = android::getenv(context, "ANDROID_PRINTF_LOG");
+ const char* logFormat = getenv("ANDROID_PRINTF_LOG");
if (!!logFormat) {
std::unique_ptr<char, void (*)(void*)> formats(strdup(logFormat),
@@ -1366,41 +1044,34 @@
char* sv = nullptr; // protect against -ENOMEM above
char* arg = formats.get();
while (!!(arg = strtok_r(arg, delimiters, &sv))) {
- err = setLogFormat(context, arg);
+ err = SetLogFormat(arg);
// environment should not cause crash of logcat
- if ((err < 0) && context->error) {
- fprintf(context->error,
- "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
+ if (err < 0) {
+ fprintf(stderr, "invalid format in ANDROID_PRINTF_LOG '%s'\n", arg);
}
arg = nullptr;
if (err > 0) hasSetLogFormat = true;
}
}
if (!hasSetLogFormat) {
- setLogFormat(context, "threadtime");
+ SetLogFormat("threadtime");
}
}
if (forceFilters.size()) {
- err = android_log_addFilterString(context->logformat,
- forceFilters.c_str());
+ err = android_log_addFilterString(logformat_.get(), forceFilters.c_str());
if (err < 0) {
- logcat_panic(context, HELP_FALSE,
- "Invalid filter expression in logcat args\n");
- goto exit;
+ LogcatPanic(HELP_FALSE, "Invalid filter expression in logcat args\n");
}
} else if (argc == optind) {
// Add from environment variable
- const char* env_tags_orig = android::getenv(context, "ANDROID_LOG_TAGS");
+ const char* env_tags_orig = getenv("ANDROID_LOG_TAGS");
if (!!env_tags_orig) {
- err = android_log_addFilterString(context->logformat,
- env_tags_orig);
+ err = android_log_addFilterString(logformat_.get(), env_tags_orig);
if (err < 0) {
- logcat_panic(context, HELP_TRUE,
- "Invalid filter expression in ANDROID_LOG_TAGS\n");
- goto exit;
+ LogcatPanic(HELP_TRUE, "Invalid filter expression in ANDROID_LOG_TAGS\n");
}
}
} else {
@@ -1411,16 +1082,14 @@
// skip stdout redirections of _all_ kinds
if (argv[i][0] == '>') continue;
- err = android_log_addFilterString(context->logformat, argv[i]);
+ err = android_log_addFilterString(logformat_.get(), argv[i]);
if (err < 0) {
- logcat_panic(context, HELP_TRUE,
- "Invalid filter expression '%s'\n", argv[i]);
- goto exit;
+ LogcatPanic(HELP_TRUE, "Invalid filter expression '%s'\n", argv[i]);
}
}
}
- dev = context->devices;
+ dev = devices_;
if (tail_time != log_time::EPOCH) {
logger_list = android_logger_list_alloc_time(mode, tail_time, pid);
} else {
@@ -1439,21 +1108,18 @@
}
if (clearLog || setId) {
- if (context->outputFileName) {
- int maxRotationCountDigits =
- (context->maxRotatedLogs > 0) ?
- (int)(floor(log10(context->maxRotatedLogs) + 1)) :
- 0;
+ if (output_file_name_) {
+ int max_rotation_count_digits =
+ max_rotated_logs_ > 0 ? (int)(floor(log10(max_rotated_logs_) + 1)) : 0;
- for (int i = context->maxRotatedLogs ; i >= 0 ; --i) {
+ for (int i = max_rotated_logs_; i >= 0; --i) {
std::string file;
if (!i) {
- file = android::base::StringPrintf(
- "%s", context->outputFileName);
+ file = output_file_name_;
} else {
- file = android::base::StringPrintf("%s.%.*d",
- context->outputFileName, maxRotationCountDigits, i);
+ file = StringPrintf("%s.%.*d", output_file_name_, max_rotation_count_digits,
+ i);
}
if (!file.length()) {
@@ -1497,36 +1163,25 @@
readable_format.first, readable_format.second,
(int)LOGGER_ENTRY_MAX_LEN,
(int)LOGGER_ENTRY_MAX_PAYLOAD);
- TEMP_FAILURE_RETRY(write(context->output_fd,
- str.data(), str.length()));
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), str.data(), str.length()));
}
}
dev = dev->next;
}
- context->retval = EXIT_SUCCESS;
-
// report any errors in the above loop and exit
if (openDeviceFail) {
- logcat_panic(context, HELP_FALSE,
- "Unable to open log device '%s'\n", openDeviceFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "Unable to open log device '%s'\n", openDeviceFail);
}
if (clearFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to clear the '%s' log\n", clearFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to clear the '%s' log\n", clearFail);
}
if (setSizeFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to set the '%s' log size\n", setSizeFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to set the '%s' log size\n", setSizeFail);
}
if (getSizeFail) {
- logcat_panic(context, HELP_FALSE,
- "failed to get the readable '%s' log size", getSizeFail);
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to get the readable '%s' log size", getSizeFail);
}
if (setPruneList) {
@@ -1537,15 +1192,13 @@
if (asprintf(&buf, "%-*s", (int)(bLen - 1), setPruneList) > 0) {
buf[len] = '\0';
if (android_logger_set_prune_list(logger_list, buf, bLen)) {
- logcat_panic(context, HELP_FALSE,
- "failed to set the prune list");
+ LogcatPanic(HELP_FALSE, "failed to set the prune list");
}
free(buf);
} else {
- logcat_panic(context, HELP_FALSE,
- "failed to set the prune list (alloc)");
+ LogcatPanic(HELP_FALSE, "failed to set the prune list (alloc)");
}
- goto close;
+ return EXIT_SUCCESS;
}
if (printStatistics || getPruneList) {
@@ -1574,8 +1227,7 @@
}
if (!buf) {
- logcat_panic(context, HELP_FALSE, "failed to read data");
- goto close;
+ LogcatPanic(HELP_FALSE, "failed to read data");
}
// remove trailing FF
@@ -1592,149 +1244,68 @@
}
len = strlen(cp);
- TEMP_FAILURE_RETRY(write(context->output_fd, cp, len));
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), cp, len));
delete[] buf;
- goto close;
+ return EXIT_SUCCESS;
}
- if (getLogSize || setLogSize || clearLog) goto close;
+ if (getLogSize || setLogSize || clearLog) return EXIT_SUCCESS;
- setupOutputAndSchedulingPolicy(context, !(mode & ANDROID_LOG_NONBLOCK));
- if (context->stop) goto close;
-
- // LOG_EVENT_INT(10, 12345);
- // LOG_EVENT_LONG(11, 0x1122334455667788LL);
- // LOG_EVENT_STRING(0, "whassup, doc?");
+ SetupOutputAndSchedulingPolicy(!(mode & ANDROID_LOG_NONBLOCK));
dev = nullptr;
- while (!context->stop &&
- (!context->maxCount || (context->printCount < context->maxCount))) {
+ while (!max_count_ || print_count_ < max_count_) {
struct log_msg log_msg;
int ret = android_logger_list_read(logger_list, &log_msg);
if (!ret) {
- logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret < 0) {
if (ret == -EAGAIN) break;
if (ret == -EIO) {
- logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
- logcat_panic(context, HELP_FALSE, "read: unexpected length.\n");
- break;
+ LogcatPanic(HELP_FALSE, "read: unexpected length.\n");
}
- logcat_panic(context, HELP_FALSE, "logcat read failure\n");
- break;
+ LogcatPanic(HELP_FALSE, "logcat read failure\n");
}
log_device_t* d;
- for (d = context->devices; d; d = d->next) {
+ for (d = devices_; d; d = d->next) {
if (android_name_to_log_id(d->device) == log_msg.id()) break;
}
if (!d) {
- context->devCount = 2; // set to Multiple
+ dev_count_ = 2; // set to Multiple
d = &unexpected;
d->binary = log_msg.id() == LOG_ID_EVENTS;
}
if (dev != d) {
dev = d;
- maybePrintStart(context, dev, printDividers);
- if (context->stop) break;
+ MaybePrintStart(dev, printDividers);
}
- if (context->printBinary) {
- printBinary(context, &log_msg);
+ if (print_binary_) {
+ TEMP_FAILURE_RETRY(write(output_fd_.get(), &log_msg, log_msg.len()));
} else {
- processBuffer(context, dev, &log_msg);
+ ProcessBuffer(dev, &log_msg);
}
}
-
-close:
- // Short and sweet. Implemented generic version in android_logcat_destroy.
- while (!!(dev = context->devices)) {
- context->devices = dev->next;
- delete dev;
- }
- android_logger_list_free(logger_list);
-
-exit:
- // close write end of pipe to help things along
- if (context->output_fd == context->fds[1]) {
- android::close_output(context);
- }
- if (context->error_fd == context->fds[1]) {
- android::close_error(context);
- }
- if (context->fds[1] >= 0) {
- // NB: should be closed by the above
- int save_errno = errno;
- close(context->fds[1]);
- errno = save_errno;
- context->fds[1] = -1;
- }
- context->thread_stopped = true;
- return context->retval;
+ return EXIT_SUCCESS;
}
-// Can block
-int android_logcat_run_command(android_logcat_context ctx,
- int output, int error,
- int argc, char* const* argv,
- char* const* envp) {
- android_logcat_context_internal* context = ctx;
-
- context->output_fd = output;
- context->error_fd = error;
- context->argc = argc;
- context->argv = argv;
- context->envp = envp;
- context->stop = false;
- context->thread_stopped = false;
- return __logcat(context);
+int RunLogcat(int argc, char** argv) {
+ Logcat logcat;
+ return logcat.Run(argc, argv);
}
-// Finished with context
-int android_logcat_destroy(android_logcat_context* ctx) {
- android_logcat_context_internal* context = *ctx;
-
- if (!context) return -EBADF;
-
- *ctx = nullptr;
-
- context->stop = true;
-
- while (context->thread_stopped == false) {
- // Makes me sad, replace thread_stopped with semaphore. Short lived.
- sched_yield();
- }
-
- context->argv_hold.clear();
- context->args.clear();
- context->envp_hold.clear();
- context->envs.clear();
- if (context->fds[0] >= 0) {
- close(context->fds[0]);
- context->fds[0] = -1;
- }
- android::close_output(context);
- android::close_error(context);
-
- if (context->fds[1] >= 0) {
- // NB: this should be closed by close_output, but just in case...
- close(context->fds[1]);
- context->fds[1] = -1;
- }
-
- android_closeEventTagMap(context->eventTagMap);
-
+Logcat::~Logcat() {
// generic cleanup of devices list to handle all possible dirty cases
log_device_t* dev;
- while (!!(dev = context->devices)) {
+ while (!!(dev = devices_)) {
struct logger_list* logger_list = dev->logger_list;
if (logger_list) {
for (log_device_t* d = dev; d; d = d->next) {
@@ -1742,13 +1313,7 @@
}
android_logger_list_free(logger_list);
}
- context->devices = dev->next;
+ devices_ = dev->next;
delete dev;
}
-
- int retval = context->retval;
-
- free(context);
-
- return retval;
}
diff --git a/logcat/logcat.h b/logcat/logcat.h
index 85ed7da..4cc112b 100644
--- a/logcat/logcat.h
+++ b/logcat/logcat.h
@@ -16,45 +16,4 @@
#pragma once
-#include <stdio.h>
-
-/*
- * The opaque context
- */
-typedef struct android_logcat_context_internal* android_logcat_context;
-
-/* Creates a context associated with this logcat instance
- *
- * Returns a pointer to the context, or a NULL on error.
- */
-android_logcat_context create_android_logcat();
-
-/* Collects and outputs the logcat data to output and error file descriptors
- *
- * Will block, performed in-thread and in-process
- *
- * The output file descriptor variable, if greater than or equal to 0, is
- * where the output (ie: stdout) will be sent. The file descriptor is closed
- * on android_logcat_destroy which terminates the instance, or when an -f flag
- * (output redirect to a file) is present in the command. The error file
- * descriptor variable, if greater than or equal to 0, is where the error
- * stream (ie: stderr) will be sent, also closed on android_logcat_destroy.
- * The error file descriptor can be set to equal to the output file descriptor,
- * which will mix output and error stream content, and will defer closure of
- * the file descriptor on -f flag redirection. Negative values for the file
- * descriptors will use stdout and stderr FILE references respectively
- * internally, and will not close the references as noted above.
- *
- * Return value is 0 for success, non-zero for errors.
- */
-int android_logcat_run_command(android_logcat_context ctx, int output, int error, int argc,
- char* const* argv, char* const* envp);
-
-/* Finished with context
- *
- * Kill the command thread ASAP (if any), and free up all associated resources.
- *
- * Return value is the result of the android_logcat_run_command, or
- * non-zero for any errors.
- */
-int android_logcat_destroy(android_logcat_context* ctx);
+int RunLogcat(int argc, char** argv);
\ No newline at end of file
diff --git a/logcat/logcat_main.cpp b/logcat/logcat_main.cpp
index ecfa2ba..59ab716 100644
--- a/logcat/logcat_main.cpp
+++ b/logcat/logcat_main.cpp
@@ -19,12 +19,7 @@
#include "logcat.h"
-int main(int argc, char** argv, char** envp) {
- android_logcat_context ctx = create_android_logcat();
- if (!ctx) return -1;
+int main(int argc, char** argv) {
signal(SIGPIPE, exit);
- int retval = android_logcat_run_command(ctx, -1, -1, argc, argv, envp);
- int ret = android_logcat_destroy(&ctx);
- if (!ret) ret = retval;
- return ret;
+ return RunLogcat(argc, argv);
}
diff --git a/logcat/logcatd_main.cpp b/logcat/logcatd_main.cpp
index c131846..4da933f 100644
--- a/logcat/logcatd_main.cpp
+++ b/logcat/logcatd_main.cpp
@@ -23,10 +23,7 @@
#include "logcat.h"
-int main(int argc, char** argv, char** envp) {
- android_logcat_context ctx = create_android_logcat();
- if (!ctx) return -1;
-
+int main(int argc, char** argv) {
signal(SIGPIPE, exit);
// Save and detect presence of -L or --last flag
@@ -46,8 +43,7 @@
int ret = 0;
if (last) {
// Run logcat command with -L flag
- ret = android_logcat_run_command(ctx, -1, -1, argv_hold.size() - 1,
- (char* const*)&argv_hold[0], envp);
+ ret = RunLogcat(argv_hold.size() - 1, (char**)&argv_hold[0]);
// Remove -L and --last flags from argument list
for (std::vector<const char*>::iterator it = argv_hold.begin();
it != argv_hold.end();) {
@@ -62,10 +58,7 @@
}
// Run logcat command without -L flag
- int retval = android_logcat_run_command(ctx, -1, -1, argv_hold.size() - 1,
- (char* const*)&argv_hold[0], envp);
- if (!ret) ret = retval;
- retval = android_logcat_destroy(&ctx);
+ int retval = RunLogcat(argv_hold.size() - 1, (char**)&argv_hold[0]);
if (!ret) ret = retval;
return ret;
}
diff --git a/rootdir/Android.mk b/rootdir/Android.mk
index 5241730..e1bb02f 100644
--- a/rootdir/Android.mk
+++ b/rootdir/Android.mk
@@ -326,7 +326,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_SAMEPROCESS_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -342,7 +342,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_CORE_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
@@ -358,7 +358,7 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE))
include $(BUILD_SYSTEM)/base_rules.mk
-$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.com.android.vndk.current)
+$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES := $(call module-installed-files-or-guess,$(VNDK_PRIVATE_LIBRARIES),.vendor)
$(LOCAL_BUILT_MODULE):
@echo "Generate: $@"
@mkdir -p $(dir $@)
diff --git a/rootdir/init.rc b/rootdir/init.rc
index c5bf1603..9b77ce2 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -754,6 +754,7 @@
# to make it too large, since it may bring userdata loss, if they
# are not aware of using fsync()/sync() to prepare sudden power-cut.
write /sys/fs/f2fs/${dev.mnt.blk.data}/cp_interval 200
+ write /sys/fs/f2fs/${dev.mnt.blk.data}/gc_urgent_sleep_time 50
# Permissions for System Server and daemons.
chown system system /sys/power/autosleep
@@ -925,9 +926,17 @@
setprop sys.init.updatable_crashing 0
setprop apexd.status 0
+on userspace-reboot-fs-remount
+ # Make sure that vold is running.
+ # This is mostly a precaution measure in case vold for some reason wasn't running when
+ # userspace reboot was initiated.
+ start vold
+ exec - system system -- /system/bin/vdc checkpoint resetCheckpoint
+ exec - system system -- /system/bin/vdc checkpoint markBootAttempt
+ remount_userdata
+
on userspace-reboot-resume
- # TODO(b/135984674): remount userdata and reset checkpointing
- trigger nonencrypted
+ trigger userspace-reboot-fs-remount
trigger post-fs-data
trigger zygote-start
trigger early-boot
diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp
index 694b50e..ec4f6ab 100644
--- a/shell_and_utilities/Android.bp
+++ b/shell_and_utilities/Android.bp
@@ -25,7 +25,7 @@
"tcpdump",
"toolbox",
"toybox",
- "unzip",
+ "ziptool",
],
}