libcutils: remove schedgroup fds [DO NOT MERGE] am: bcb6419fc9 -s ours
am: 058188d345
Change-Id: Idea874d7b616b6e183d1e76f891b298a6e0f0668
diff --git a/.clang-format-2 b/.clang-format-2
index aab4665..41591ce 100644
--- a/.clang-format-2
+++ b/.clang-format-2
@@ -1,4 +1,5 @@
BasedOnStyle: Google
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/.clang-format-4 b/.clang-format-4
index 1497447..ae4a451 100644
--- a/.clang-format-4
+++ b/.clang-format-4
@@ -1,5 +1,6 @@
BasedOnStyle: Google
AccessModifierOffset: -2
+AllowShortFunctionsOnASingleLine: Inline
ColumnLimit: 100
CommentPragmas: NOLINT:.*
DerivePointerAlignment: false
diff --git a/base/include/android-base/properties.h b/base/include/android-base/properties.h
index 4de5e57..041586c 100644
--- a/base/include/android-base/properties.h
+++ b/base/include/android-base/properties.h
@@ -62,15 +62,14 @@
// Waits for the system property `key` to have the value `expected_value`.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
- std::chrono::milliseconds relative_timeout);
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
+ std::chrono::milliseconds relative_timeout = std::chrono::milliseconds::max());
// Waits for the system property `key` to be created.
// Times out after `relative_timeout`.
// Returns true on success, false on timeout.
-bool WaitForPropertyCreation(const std::string& key,
- std::chrono::milliseconds relative_timeout);
+bool WaitForPropertyCreation(const std::string& key, std::chrono::milliseconds relative_timeout =
+ std::chrono::milliseconds::max());
} // namespace base
} // namespace android
diff --git a/base/properties.cpp b/base/properties.cpp
index 32c0128..816bca0 100644
--- a/base/properties.cpp
+++ b/base/properties.cpp
@@ -101,22 +101,24 @@
}
// TODO: chrono_utils?
-static void DurationToTimeSpec(timespec& ts, std::chrono::nanoseconds d) {
+static void DurationToTimeSpec(timespec& ts, const std::chrono::milliseconds d) {
auto s = std::chrono::duration_cast<std::chrono::seconds>(d);
auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(d - s);
ts.tv_sec = s.count();
ts.tv_nsec = ns.count();
}
+// TODO: boot_clock?
using AbsTime = std::chrono::time_point<std::chrono::steady_clock>;
-static void UpdateTimeSpec(timespec& ts,
- const AbsTime& timeout) {
+static void UpdateTimeSpec(timespec& ts, std::chrono::milliseconds relative_timeout,
+ const AbsTime& start_time) {
auto now = std::chrono::steady_clock::now();
- auto remaining_timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(timeout - now);
- if (remaining_timeout < 0ns) {
+ auto time_elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(now - start_time);
+ if (time_elapsed >= relative_timeout) {
ts = { 0, 0 };
} else {
+ auto remaining_timeout = relative_timeout - time_elapsed;
DurationToTimeSpec(ts, remaining_timeout);
}
}
@@ -127,11 +129,7 @@
// Returns nullptr on timeout.
static const prop_info* WaitForPropertyCreation(const std::string& key,
const std::chrono::milliseconds& relative_timeout,
- AbsTime& absolute_timeout) {
- // TODO: boot_clock?
- auto now = std::chrono::steady_clock::now();
- absolute_timeout = now + relative_timeout;
-
+ const AbsTime& start_time) {
// Find the property's prop_info*.
const prop_info* pi;
unsigned global_serial = 0;
@@ -139,17 +137,16 @@
// The property doesn't even exist yet.
// Wait for a global change and then look again.
timespec ts;
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
if (!__system_property_wait(nullptr, global_serial, &global_serial, &ts)) return nullptr;
}
return pi;
}
-bool WaitForProperty(const std::string& key,
- const std::string& expected_value,
+bool WaitForProperty(const std::string& key, const std::string& expected_value,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, absolute_timeout);
+ auto start_time = std::chrono::steady_clock::now();
+ const prop_info* pi = WaitForPropertyCreation(key, relative_timeout, start_time);
if (pi == nullptr) return false;
WaitForPropertyData data;
@@ -162,7 +159,7 @@
if (data.done) return true;
// It didn't, so wait for the property to change before checking again.
- UpdateTimeSpec(ts, absolute_timeout);
+ UpdateTimeSpec(ts, relative_timeout, start_time);
uint32_t unused;
if (!__system_property_wait(pi, data.last_read_serial, &unused, &ts)) return false;
}
@@ -170,8 +167,8 @@
bool WaitForPropertyCreation(const std::string& key,
std::chrono::milliseconds relative_timeout) {
- AbsTime absolute_timeout;
- return (WaitForPropertyCreation(key, relative_timeout, absolute_timeout) != nullptr);
+ auto start_time = std::chrono::steady_clock::now();
+ return (WaitForPropertyCreation(key, relative_timeout, start_time) != nullptr);
}
} // namespace base
diff --git a/base/properties_test.cpp b/base/properties_test.cpp
index 1bbe482..de5f3dc 100644
--- a/base/properties_test.cpp
+++ b/base/properties_test.cpp
@@ -151,6 +151,38 @@
ASSERT_LT(std::chrono::duration_cast<std::chrono::milliseconds>(t1 - t0), 600ms);
}
+TEST(properties, WaitForProperty_MaxTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Test that this does not immediately return false due to overflow issues with the timeout.
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b"));
+ thread.join();
+}
+
+TEST(properties, WaitForProperty_NegativeTimeout) {
+ std::atomic<bool> flag{false};
+ std::thread thread([&]() {
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "a");
+ while (!flag) std::this_thread::yield();
+ std::this_thread::sleep_for(500ms);
+ android::base::SetProperty("debug.libbase.WaitForProperty_test", "b");
+ });
+
+ ASSERT_TRUE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "a", 1s));
+ flag = true;
+ // Assert that this immediately returns with a negative timeout
+ ASSERT_FALSE(android::base::WaitForProperty("debug.libbase.WaitForProperty_test", "b", -100ms));
+ thread.join();
+}
+
TEST(properties, WaitForPropertyCreation) {
std::thread thread([&]() {
std::this_thread::sleep_for(100ms);
diff --git a/demangle/demangle.cpp b/demangle/demangle.cpp
index be4d2dd..66e5e58 100644
--- a/demangle/demangle.cpp
+++ b/demangle/demangle.cpp
@@ -20,22 +20,25 @@
#include <string.h>
#include <unistd.h>
+#include <cctype>
#include <string>
#include <demangle.h>
extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*);
-void usage(const char* prog_name) {
- printf("Usage: %s [-c] <NAME_TO_DEMANGLE>\n", prog_name);
- printf(" -c\n");
- printf(" Compare the results of __cxa_demangle against the current\n");
- printf(" demangler.\n");
+static void Usage(const char* prog_name) {
+ printf("usage: %s [-c] [NAME_TO_DEMANGLE...]\n", prog_name);
+ printf("\n");
+ printf("Demangles C++ mangled names if supplied on the command-line, or found\n");
+ printf("reading from stdin otherwise.\n");
+ printf("\n");
+ printf("-c\tCompare against __cxa_demangle\n");
+ printf("\n");
}
-std::string DemangleWithCxa(const char* name) {
+static std::string DemangleWithCxa(const char* name) {
const char* cxa_demangle = __cxa_demangle(name, nullptr, nullptr, nullptr);
-
if (cxa_demangle == nullptr) {
return name;
}
@@ -54,6 +57,49 @@
return demangled_str;
}
+static void Compare(const char* name, const std::string& demangled_name) {
+ std::string cxa_demangled_name(DemangleWithCxa(name));
+ if (cxa_demangled_name != demangled_name) {
+ printf("\nMismatch!\n");
+ printf("\tmangled name: %s\n", name);
+ printf("\tour demangle: %s\n", demangled_name.c_str());
+ printf("\tcxa demangle: %s\n", cxa_demangled_name.c_str());
+ exit(1);
+ }
+}
+
+static int Filter(bool compare) {
+ char* line = nullptr;
+ size_t line_length = 0;
+
+ while ((getline(&line, &line_length, stdin)) != -1) {
+ char* p = line;
+ char* name;
+ while ((name = strstr(p, "_Z")) != nullptr) {
+ // Output anything before the identifier.
+ *name = 0;
+ printf("%s", p);
+ *name = '_';
+
+ // Extract the identifier.
+ p = name;
+ while (*p && (std::isalnum(*p) || *p == '_' || *p == '.' || *p == '$')) ++p;
+
+ // Demangle and output.
+ std::string identifier(name, p);
+ std::string demangled_name = demangle(identifier.c_str());
+ printf("%s", demangled_name.c_str());
+
+ if (compare) Compare(identifier.c_str(), demangled_name);
+ }
+ // Output anything after the last identifier.
+ printf("%s", p);
+ }
+
+ free(line);
+ return 0;
+}
+
int main(int argc, char** argv) {
#ifdef __BIONIC__
const char* prog_name = getprogname();
@@ -67,31 +113,21 @@
if (opt_char == 'c') {
compare = true;
} else {
- usage(prog_name);
+ Usage(prog_name);
return 1;
}
}
- if (optind >= argc || argc - optind != 1) {
- printf("Must supply a single argument.\n\n");
- usage(prog_name);
- return 1;
- }
- const char* name = argv[optind];
- std::string demangled_name = demangle(name);
+ // With no arguments, act as a filter.
+ if (optind == argc) return Filter(compare);
- printf("%s\n", demangled_name.c_str());
+ // Otherwise demangle each argument.
+ while (optind < argc) {
+ const char* name = argv[optind++];
+ std::string demangled_name = demangle(name);
+ printf("%s\n", demangled_name.c_str());
- if (compare) {
- std::string cxa_demangle_str(DemangleWithCxa(name));
-
- if (cxa_demangle_str != demangled_name) {
- printf("Mismatch\n");
- printf("cxa demangle: %s\n", cxa_demangle_str.c_str());
- return 1;
- } else {
- printf("Match\n");
- }
+ if (compare) Compare(name, demangled_name);
}
return 0;
}
diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp
index 5b2f218..cffa6ce 100644
--- a/fs_mgr/fs_mgr_boot_config.cpp
+++ b/fs_mgr/fs_mgr_boot_config.cpp
@@ -56,7 +56,7 @@
return true;
}
- LERROR << "Error finding '" << key << "' in device tree";
+ LINFO << "Error finding '" << key << "' in device tree";
}
return false;
diff --git a/init/Android.mk b/init/Android.mk
index b52c949..1ca88d7 100644
--- a/init/Android.mk
+++ b/init/Android.mk
@@ -16,6 +16,14 @@
-DREBOOT_BOOTLOADER_ON_PANIC=0
endif
+ifneq (,$(filter eng,$(TARGET_BUILD_VARIANT)))
+init_options += \
+ -DSHUTDOWN_ZERO_TIMEOUT=1
+else
+init_options += \
+ -DSHUTDOWN_ZERO_TIMEOUT=0
+endif
+
init_options += -DLOG_UEVENTS=0
init_cflags += \
diff --git a/init/reboot.cpp b/init/reboot.cpp
index 2844d78..e34abdb 100644
--- a/init/reboot.cpp
+++ b/init/reboot.cpp
@@ -341,7 +341,14 @@
}
/* TODO update default waiting time based on usage data */
- unsigned int shutdownTimeout = android::base::GetUintProperty("ro.build.shutdown_timeout", 10u);
+ constexpr unsigned int shutdownTimeoutDefault = 10;
+ unsigned int shutdownTimeout = shutdownTimeoutDefault;
+ if (SHUTDOWN_ZERO_TIMEOUT) { // eng build
+ shutdownTimeout = 0;
+ } else {
+ shutdownTimeout =
+ android::base::GetUintProperty("ro.build.shutdown_timeout", shutdownTimeoutDefault);
+ }
LOG(INFO) << "Shutdown timeout: " << shutdownTimeout;
static const constexpr char* shutdown_critical_services[] = {"vold", "watchdogd"};
diff --git a/libcutils/canned_fs_config.c b/libcutils/canned_fs_config.c
index e0e6a34..96ca566 100644
--- a/libcutils/canned_fs_config.c
+++ b/libcutils/canned_fs_config.c
@@ -17,6 +17,7 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -41,7 +42,7 @@
}
int load_canned_fs_config(const char* fn) {
- char line[PATH_MAX + 200];
+ char buf[PATH_MAX + 200];
FILE* f;
f = fopen(fn, "r");
@@ -50,17 +51,21 @@
return -1;
}
- while (fgets(line, sizeof(line), f)) {
+ while (fgets(buf, sizeof(buf), f)) {
Path* p;
char* token;
+ char* line = buf;
+ bool rootdir;
while (canned_used >= canned_alloc) {
canned_alloc = (canned_alloc+1) * 2;
canned_data = (Path*) realloc(canned_data, canned_alloc * sizeof(Path));
}
p = canned_data + canned_used;
- p->path = strdup(strtok(line, " "));
- p->uid = atoi(strtok(NULL, " "));
+ if (line[0] == '/') line++;
+ rootdir = line[0] == ' ';
+ p->path = strdup(rootdir ? "" : strtok(line, " "));
+ p->uid = atoi(strtok(rootdir ? line : NULL, " "));
p->gid = atoi(strtok(NULL, " "));
p->mode = strtol(strtok(NULL, " "), NULL, 8); // mode is in octal
p->capabilities = 0;
diff --git a/logd/LogBufferElement.cpp b/logd/LogBufferElement.cpp
index 81356fe..04a620c 100644
--- a/logd/LogBufferElement.cpp
+++ b/logd/LogBufferElement.cpp
@@ -235,7 +235,9 @@
}
iovec[1].iov_len = entry.len;
- log_time retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mRealTime;
+ log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
+ ? FLUSH_ERROR
+ : mRealTime;
if (buffer) free(buffer);
diff --git a/tzdatacheck/tzdatacheck.cpp b/tzdatacheck/tzdatacheck.cpp
index 381df5a..8fcd17f 100644
--- a/tzdatacheck/tzdatacheck.cpp
+++ b/tzdatacheck/tzdatacheck.cpp
@@ -30,6 +30,19 @@
#include "android-base/logging.h"
+// The name of the directory that holds a staged time zone update distro. If this exists it should
+// replace the one in CURRENT_DIR_NAME.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* STAGED_DIR_NAME = "/staged";
+
+// The name of the directory that holds the (optional) installed time zone update distro.
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* CURRENT_DIR_NAME = "/current";
+
+// The name of a file in the staged dir that indicates the staged operation is an "uninstall".
+// See also libcore.tzdata.update2.TimeZoneDistroInstaller.
+static const char* UNINSTALL_TOMBSTONE_FILE_NAME = "/STAGED_UNINSTALL_TOMBSTONE";
+
// The name of the file containing the distro version information.
// See also libcore.tzdata.shared2.TimeZoneDistro / libcore.tzdata.shared2.DistroVersion.
static const char* DISTRO_VERSION_FILENAME = "/distro_version";
@@ -75,7 +88,6 @@
static const char TZ_DATA_HEADER_PREFIX[] = "tzdata";
static const size_t TZ_DATA_HEADER_PREFIX_LEN = sizeof(TZ_DATA_HEADER_PREFIX) - 1; // exclude \0
-
static void usage() {
std::cerr << "Usage: tzdatacheck SYSTEM_TZ_DIR DATA_TZ_DIR\n"
"\n"
@@ -184,7 +196,7 @@
return 0;
}
-enum PathStatus { ERR, NONE, IS_DIR, NOT_DIR };
+enum PathStatus { ERR, NONE, IS_DIR, IS_REG, UNKNOWN };
static PathStatus checkPath(const std::string& path) {
struct stat buf;
@@ -195,7 +207,31 @@
}
return NONE;
}
- return S_ISDIR(buf.st_mode) ? IS_DIR : NOT_DIR;
+ return S_ISDIR(buf.st_mode) ? IS_DIR : S_ISREG(buf.st_mode) ? IS_REG : UNKNOWN;
+}
+
+/*
+ * Deletes fileToDelete and returns true if it is successful. If fileToDelete is not a file or
+ * cannot be accessed this method returns false.
+ */
+static bool deleteFile(const std::string& fileToDelete) {
+ // Check whether the file exists.
+ PathStatus pathStatus = checkPath(fileToDelete);
+ if (pathStatus == NONE) {
+ LOG(INFO) << "Path " << fileToDelete << " does not exist";
+ return true;
+ }
+ if (pathStatus != IS_REG) {
+ LOG(WARNING) << "Path " << fileToDelete << " failed to stat() or is not a file.";
+ return false;
+ }
+
+ // Attempt the deletion.
+ int rc = unlink(fileToDelete.c_str());
+ if (rc != 0) {
+ PLOG(WARNING) << "unlink() failed for " << fileToDelete;
+ }
+ return rc == 0;
}
/*
@@ -260,8 +296,7 @@
std::string dataUpdatesDirName(dataZoneInfoDir);
dataUpdatesDirName += "/updates";
LOG(INFO) << "Removing: " << dataUpdatesDirName;
- bool deleted = deleteDir(dataUpdatesDirName);
- if (!deleted) {
+ if (!deleteDir(dataUpdatesDirName)) {
LOG(WARNING) << "Deletion of install metadata " << dataUpdatesDirName
<< " was not successful";
}
@@ -270,14 +305,151 @@
/*
* Deletes the timezone update distro directory.
*/
-static void deleteUpdateDistroDir(std::string& distroDirName) {
+static void deleteUpdateDistroDir(const std::string& distroDirName) {
LOG(INFO) << "Removing: " << distroDirName;
- bool deleted = deleteDir(distroDirName);
- if (!deleted) {
+ if (!deleteDir(distroDirName)) {
LOG(WARNING) << "Deletion of distro dir " << distroDirName << " was not successful";
}
}
+static void handleStagedUninstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an uninstall.";
+
+ // Delete the current install directory.
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is unexpected: No uninstall should be staged if there is nothing to
+ // uninstall. Carry on anyway.
+ LOG(WARNING) << "No current install to delete.";
+ break;
+ case IS_DIR:
+ // This is normal. Delete the current install dir.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete or not. We don't
+ // delete the staged operation so it will be retried next boot unless overridden.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Delete the staged uninstall dir.
+ if (!deleteDir(dataStagedDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens we don't know whether we were able to delete the staged operation
+ // or not.
+ return;
+ }
+ LOG(INFO) << "Staged uninstall complete.";
+}
+
+static void handleStagedInstall(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName,
+ const PathStatus dataCurrentDirStatus) {
+ LOG(INFO) << "Staged operation is an install.";
+
+ switch (dataCurrentDirStatus) {
+ case NONE:
+ // This is expected: This is the first install.
+ LOG(INFO) << "No current install to replace.";
+ break;
+ case IS_DIR:
+ // This is expected: We are replacing an existing install.
+ // Delete the current dir so we can replace it.
+ if (!deleteDir(dataCurrentDirName)) {
+ LOG(WARNING) << "Deletion of current distro " << dataCurrentDirName
+ << " was not successful";
+ // If this happens, we cannot proceed.
+ return;
+ }
+ break;
+ case IS_REG:
+ default:
+ // This is unexpected: We can try to delete the unexpected file and carry on.
+ LOG(WARNING) << "Current distro dir " << dataCurrentDirName
+ << " is not actually a directory. Attempting deletion.";
+ if (!deleteFile(dataCurrentDirName)) {
+ LOG(WARNING) << "Could not delete " << dataCurrentDirName;
+ return;
+ }
+ break;
+ }
+
+ // Move the staged dir so it is the new current dir, completing the install.
+ LOG(INFO) << "Moving " << dataStagedDirName << " to " << dataCurrentDirName;
+ int rc = rename(dataStagedDirName.c_str(), dataCurrentDirName.c_str());
+ if (rc == -1) {
+ PLOG(WARNING) << "Unable to rename directory from " << dataStagedDirName << " to "
+ << &dataCurrentDirName[0];
+ return;
+ }
+
+ LOG(INFO) << "Staged install complete.";
+}
+/*
+ * Process a staged operation if there is one.
+ */
+static void processStagedOperation(const std::string& dataStagedDirName,
+ const std::string& dataCurrentDirName) {
+ PathStatus dataStagedDirStatus = checkPath(dataStagedDirName);
+
+ // Exit early for the common case.
+ if (dataStagedDirStatus == NONE) {
+ LOG(DEBUG) << "No staged time zone operation.";
+ return;
+ }
+
+ // Check known directory names are in a good starting state.
+ if (dataStagedDirStatus != IS_DIR) {
+ LOG(WARNING) << "Staged distro dir " << dataStagedDirName
+ << " could not be accessed or is not a directory."
+ << " stagedDirStatus=" << dataStagedDirStatus;
+ return;
+ }
+
+ // dataStagedDirStatus == IS_DIR.
+
+ // Work out whether there is anything currently installed.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ if (dataCurrentDirStatus == ERR) {
+ LOG(WARNING) << "Current install dir " << dataCurrentDirName << " could not be accessed"
+ << " dataCurrentDirStatus=" << dataCurrentDirStatus;
+ return;
+ }
+
+ // We must perform the staged operation.
+
+ // Check to see if the staged directory contains an uninstall or an install operation.
+ std::string uninstallTombStoneFile(dataStagedDirName);
+ uninstallTombStoneFile += UNINSTALL_TOMBSTONE_FILE_NAME;
+ int uninstallTombStoneFileStatus = checkPath(uninstallTombStoneFile);
+ if (uninstallTombStoneFileStatus != IS_REG && uninstallTombStoneFileStatus != NONE) {
+ // Error case.
+ LOG(WARNING) << "Unable to determine if the staged operation is an uninstall.";
+ return;
+ }
+ if (uninstallTombStoneFileStatus == IS_REG) {
+ handleStagedUninstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ } else {
+ // uninstallTombStoneFileStatus == NONE meaning this is a staged install.
+ handleStagedInstall(dataStagedDirName, dataCurrentDirName, dataCurrentDirStatus);
+ }
+}
+
/*
* After a platform update it is likely that timezone data found on the system partition will be
* newer than the version found in the data partition. This tool detects this case and removes the
@@ -300,15 +472,25 @@
const char* systemZoneInfoDir = argv[1];
const char* dataZoneInfoDir = argv[2];
- // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ std::string dataStagedDirName(dataZoneInfoDir);
+ dataStagedDirName += STAGED_DIR_NAME;
+
std::string dataCurrentDirName(dataZoneInfoDir);
- dataCurrentDirName += "/current";
- int dataCurrentDirStatus = checkPath(dataCurrentDirName);
+ dataCurrentDirName += CURRENT_DIR_NAME;
+
+ // Check for an process any staged operation.
+ // If the staged operation could not be handled we still have to validate the current installed
+ // directory so we do not check for errors and do not quit early.
+ processStagedOperation(dataStagedDirName, dataCurrentDirName);
+
+ // Check the distro directory exists. If it does not, exit quickly: nothing to do.
+ PathStatus dataCurrentDirStatus = checkPath(dataCurrentDirName);
if (dataCurrentDirStatus == NONE) {
LOG(INFO) << "timezone distro dir " << dataCurrentDirName
<< " does not exist. No action required.";
return 0;
}
+
// If the distro directory path is not a directory or we can't stat() the path, exit with a
// warning: either there's a problem accessing storage or the world is not as it should be;
// nothing to do.