From 3bbb20f557790c015e44098098375eb6cc376a42 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Tue, 27 Feb 2018 15:56:11 -0800 Subject: Add a singleton CacheLocation to replace the hard coded locations This class allows us to set the following locations dynamically: cache_temp_source, last_command_file, stash_directory_base. In the updater's main function, we reset the values of these variables to their default locations in /cache; while we can set them to temp files in unit tests or host simulation. Test: unit tests pass Change-Id: I528652650caa41373617ab055d41b1f1a4ec0f87 --- applypatch/applypatch.cpp | 11 +++-- applypatch/freecache.cpp | 3 +- applypatch/include/applypatch/applypatch.h | 6 --- otautil/Android.bp | 1 + otautil/cache_location.cpp | 32 +++++++++++++ otautil/include/otautil/cache_location.h | 72 ++++++++++++++++++++++++++++++ tests/component/applypatch_test.cpp | 5 ++- tests/component/updater_test.cpp | 21 ++++++--- updater/blockimg.cpp | 9 ++-- updater/include/updater/blockimg.h | 1 - updater/updater.cpp | 5 +++ 11 files changed, 139 insertions(+), 27 deletions(-) create mode 100644 otautil/cache_location.cpp create mode 100644 otautil/include/otautil/cache_location.h diff --git a/applypatch/applypatch.cpp b/applypatch/applypatch.cpp index 73701abc9..7645a4005 100644 --- a/applypatch/applypatch.cpp +++ b/applypatch/applypatch.cpp @@ -40,10 +40,9 @@ #include "edify/expr.h" #include "otafault/ota_io.h" +#include "otautil/cache_location.h" #include "otautil/print_sha1.h" -std::string cache_temp_source = "/cache/saved.file"; - static int LoadPartitionContents(const std::string& filename, FileContents* file); static size_t FileSink(const unsigned char* data, size_t len, int fd); static int GenerateTarget(const FileContents& source_file, const std::unique_ptr& patch, @@ -404,7 +403,7 @@ int applypatch_check(const char* filename, const std::vector& patch // If the source file is missing or corrupted, it might be because we were killed in the middle // of patching it. A copy of it should have been made in cache_temp_source. If that file // exists and matches the sha1 we're looking for, the check still passes. - if (LoadFileContents(cache_temp_source.c_str(), &file) != 0) { + if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &file) != 0) { printf("failed to load cache file\n"); return 1; } @@ -526,7 +525,7 @@ int applypatch(const char* source_filename, const char* target_filename, printf("source file is bad; trying copy\n"); FileContents copy_file; - if (LoadFileContents(cache_temp_source.c_str(), ©_file) < 0) { + if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), ©_file) < 0) { printf("failed to read copy file\n"); return 1; } @@ -621,7 +620,7 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr printf("not enough free space on /cache\n"); return 1; } - if (SaveFileContents(cache_temp_source.c_str(), &source_file) < 0) { + if (SaveFileContents(CacheLocation::location().cache_temp_source().c_str(), &source_file) < 0) { printf("failed to back up source file\n"); return 1; } @@ -667,7 +666,7 @@ static int GenerateTarget(const FileContents& source_file, const std::unique_ptr } // Delete the backup copy of the source. - unlink(cache_temp_source.c_str()); + unlink(CacheLocation::location().cache_temp_source().c_str()); // Success! return 0; diff --git a/applypatch/freecache.cpp b/applypatch/freecache.cpp index ec1d20cec..ea364d8e6 100644 --- a/applypatch/freecache.cpp +++ b/applypatch/freecache.cpp @@ -33,6 +33,7 @@ #include #include "applypatch/applypatch.h" +#include "otautil/cache_location.h" static int EliminateOpenFiles(std::set* files) { std::unique_ptr d(opendir("/proc"), closedir); @@ -92,7 +93,7 @@ static std::set FindExpendableFiles() { // We can't delete cache_temp_source; if it's there we might have restarted during // installation and could be depending on it to be there. - if (path == cache_temp_source) { + if (path == CacheLocation::location().cache_temp_source()) { continue; } diff --git a/applypatch/include/applypatch/applypatch.h b/applypatch/include/applypatch/applypatch.h index c8ad91505..912ead1fa 100644 --- a/applypatch/include/applypatch/applypatch.h +++ b/applypatch/include/applypatch/applypatch.h @@ -34,12 +34,6 @@ struct FileContents { std::vector data; }; -// When there isn't enough room on the target filesystem to hold the patched version of the file, -// we copy the original here and delete it to free up space. If the expected source file doesn't -// exist, or is corrupted, we look to see if the cached file contains the bits we want and use it as -// the source instead. The default location for the cached source is "/cache/saved.file". -extern std::string cache_temp_source; - using SinkFn = std::function; // applypatch.cpp diff --git a/otautil/Android.bp b/otautil/Android.bp index 5efb12d60..75cf69148 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -21,6 +21,7 @@ cc_library_static { "SysUtil.cpp", "DirUtil.cpp", "ThermalUtil.cpp", + "cache_location.cpp", "rangeset.cpp", ], diff --git a/otautil/cache_location.cpp b/otautil/cache_location.cpp new file mode 100644 index 000000000..8f289487f --- /dev/null +++ b/otautil/cache_location.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otautil/cache_location.h" + +constexpr const char kDefaultCacheTempSource[] = "/cache/saved.file"; +constexpr const char kDefaultLastCommandFile[] = "/cache/recovery/last_command"; +constexpr const char kDefaultStashDirectoryBase[] = "/cache/recovery"; + +CacheLocation& CacheLocation::location() { + static CacheLocation cache_location; + return cache_location; +} + +void CacheLocation::ResetLocations() { + cache_temp_source_ = kDefaultCacheTempSource; + last_command_file_ = kDefaultLastCommandFile; + stash_directory_base_ = kDefaultStashDirectoryBase; +} diff --git a/otautil/include/otautil/cache_location.h b/otautil/include/otautil/cache_location.h new file mode 100644 index 000000000..85e0d485c --- /dev/null +++ b/otautil/include/otautil/cache_location.h @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _OTAUTIL_OTAUTIL_CACHE_LOCATION_H_ +#define _OTAUTIL_OTAUTIL_CACHE_LOCATION_H_ + +#include + +#include "android-base/macros.h" + +// A singleton class to maintain the update related locations. The locations should be only set +// once at the start of the program. +class CacheLocation { + public: + static CacheLocation& location(); + + // Reset the locations to their default values. + void ResetLocations(); + + // getter and setter functions. + std::string cache_temp_source() const { + return cache_temp_source_; + } + void set_cache_temp_source(const std::string& temp_source) { + cache_temp_source_ = temp_source; + } + + std::string last_command_file() const { + return last_command_file_; + } + void set_last_command_file(const std::string& last_command) { + last_command_file_ = last_command; + } + + std::string stash_directory_base() const { + return stash_directory_base_; + } + void set_stash_directory_base(const std::string& base) { + stash_directory_base_ = base; + } + + private: + CacheLocation() {} + DISALLOW_COPY_AND_ASSIGN(CacheLocation); + + // When there isn't enough room on the target filesystem to hold the patched version of the file, + // we copy the original here and delete it to free up space. If the expected source file doesn't + // exist, or is corrupted, we look to see if the cached file contains the bits we want and use it + // as the source instead. The default location for the cached source is "/cache/saved.file". + std::string cache_temp_source_; + + // Location to save the last command that stashes blocks. + std::string last_command_file_; + + // The base directory to write stashes during update. + std::string stash_directory_base_; +}; + +#endif // _OTAUTIL_OTAUTIL_CACHE_LOCATION_H_ diff --git a/tests/component/applypatch_test.cpp b/tests/component/applypatch_test.cpp index 21c9a52dc..b6d092557 100644 --- a/tests/component/applypatch_test.cpp +++ b/tests/component/applypatch_test.cpp @@ -35,6 +35,7 @@ #include "applypatch/applypatch.h" #include "applypatch/applypatch_modes.h" #include "common/test_constants.h" +#include "otautil/cache_location.h" #include "otautil/print_sha1.h" static void sha1sum(const std::string& fname, std::string* sha1, size_t* fsize = nullptr) { @@ -93,14 +94,14 @@ class ApplyPatchCacheTest : public ApplyPatchTest { protected: void SetUp() override { ApplyPatchTest::SetUp(); - cache_temp_source = old_file; + CacheLocation::location().set_cache_temp_source(old_file); } }; class ApplyPatchModesTest : public ::testing::Test { protected: void SetUp() override { - cache_temp_source = cache_source.path; + CacheLocation::location().set_cache_temp_source(cache_source.path); } TemporaryFile cache_source; diff --git a/tests/component/updater_test.cpp b/tests/component/updater_test.cpp index 448fe4935..5bfd7cb40 100644 --- a/tests/component/updater_test.cpp +++ b/tests/component/updater_test.cpp @@ -41,6 +41,7 @@ #include "common/test_constants.h" #include "edify/expr.h" #include "otautil/SysUtil.h" +#include "otautil/cache_location.h" #include "otautil/error_code.h" #include "otautil/print_sha1.h" #include "updater/blockimg.h" @@ -104,7 +105,16 @@ class UpdaterTest : public ::testing::Test { RegisterBuiltins(); RegisterInstallFunctions(); RegisterBlockImageFunctions(); + + // Mock the location of last_command_file. + CacheLocation::location().set_cache_temp_source(temp_saved_source_.path); + CacheLocation::location().set_last_command_file(temp_last_command_.path); + CacheLocation::location().set_stash_directory_base(temp_stash_base_.path); } + + TemporaryFile temp_saved_source_; + TemporaryFile temp_last_command_; + TemporaryDir temp_stash_base_; }; TEST_F(UpdaterTest, getprop) { @@ -542,7 +552,7 @@ TEST_F(UpdaterTest, block_image_update_fail) { expect("", script.c_str(), kNoCause, &updater_info); // Updater generates the stash name based on the input file name. std::string name_digest = get_sha1(update_file.path); - std::string stash_base = "/cache/recovery/" + name_digest; + std::string stash_base = std::string(temp_stash_base_.path) + "/" + name_digest; ASSERT_EQ(0, access(stash_base.c_str(), F_OK)); ASSERT_EQ(-1, access((stash_base + src_hash).c_str(), F_OK)); ASSERT_EQ(0, rmdir(stash_base.c_str())); @@ -709,8 +719,7 @@ TEST_F(UpdaterTest, brotli_new_data) { } TEST_F(UpdaterTest, last_command_update) { - TemporaryFile temp_file; - last_command_file = temp_file.path; + std::string last_command_file = CacheLocation::location().last_command_file(); std::string block1 = std::string(4096, '1'); std::string block2 = std::string(4096, '2'); @@ -797,8 +806,7 @@ TEST_F(UpdaterTest, last_command_update) { } TEST_F(UpdaterTest, last_command_update_unresumable) { - TemporaryFile temp_file; - last_command_file = temp_file.path; + std::string last_command_file = CacheLocation::location().last_command_file(); std::string block1 = std::string(4096, '1'); std::string block2 = std::string(4096, '2'); @@ -853,8 +861,7 @@ TEST_F(UpdaterTest, last_command_update_unresumable) { } TEST_F(UpdaterTest, last_command_verify) { - TemporaryFile temp_file; - last_command_file = temp_file.path; + std::string last_command_file = CacheLocation::location().last_command_file(); std::string block1 = std::string(4096, '1'); std::string block2 = std::string(4096, '2'); diff --git a/updater/blockimg.cpp b/updater/blockimg.cpp index 4f085b204..e93196b27 100644 --- a/updater/blockimg.cpp +++ b/updater/blockimg.cpp @@ -53,6 +53,7 @@ #include "edify/expr.h" #include "otafault/ota_io.h" +#include "otautil/cache_location.h" #include "otautil/error_code.h" #include "otautil/print_sha1.h" #include "otautil/rangeset.h" @@ -65,17 +66,15 @@ #define DEBUG_ERASE 0 static constexpr size_t BLOCKSIZE = 4096; -static constexpr const char* STASH_DIRECTORY_BASE = "/cache/recovery"; static constexpr mode_t STASH_DIRECTORY_MODE = 0700; static constexpr mode_t STASH_FILE_MODE = 0600; -std::string last_command_file = "/cache/recovery/last_command"; - static CauseCode failure_type = kNoCause; static bool is_retry = false; static std::unordered_map stash_map; static void DeleteLastCommandFile() { + std::string last_command_file = CacheLocation::location().last_command_file(); if (unlink(last_command_file.c_str()) == -1 && errno != ENOENT) { PLOG(ERROR) << "Failed to unlink: " << last_command_file; } @@ -84,6 +83,7 @@ static void DeleteLastCommandFile() { // Parse the last command index of the last update and save the result to |last_command_index|. // Return true if we successfully read the index. static bool ParseLastCommandFile(int* last_command_index) { + std::string last_command_file = CacheLocation::location().last_command_file(); android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(last_command_file.c_str(), O_RDONLY))); if (fd == -1) { if (errno != ENOENT) { @@ -119,6 +119,7 @@ static bool ParseLastCommandFile(int* last_command_index) { // Update the last command index in the last_command_file if the current command writes to the // stash either explicitly or implicitly. static bool UpdateLastCommandIndex(int command_index, const std::string& command_string) { + std::string last_command_file = CacheLocation::location().last_command_file(); std::string last_command_tmp = last_command_file + ".tmp"; std::string content = std::to_string(command_index) + "\n" + command_string; android::base::unique_fd wfd( @@ -676,7 +677,7 @@ static std::string GetStashFileName(const std::string& base, const std::string& return ""; } - std::string fn(STASH_DIRECTORY_BASE); + std::string fn(CacheLocation::location().stash_directory_base()); fn += "/" + base + "/" + id + postfix; return fn; diff --git a/updater/include/updater/blockimg.h b/updater/include/updater/blockimg.h index 2cc68ce9d..71733b303 100644 --- a/updater/include/updater/blockimg.h +++ b/updater/include/updater/blockimg.h @@ -19,7 +19,6 @@ #include -extern std::string last_command_file; void RegisterBlockImageFunctions(); #endif diff --git a/updater/updater.cpp b/updater/updater.cpp index f55a0d3bd..f063e5fa1 100644 --- a/updater/updater.cpp +++ b/updater/updater.cpp @@ -34,6 +34,7 @@ #include "otafault/config.h" #include "otautil/DirUtil.h" #include "otautil/SysUtil.h" +#include "otautil/cache_location.h" #include "otautil/error_code.h" #include "updater/blockimg.h" #include "updater/install.h" @@ -168,6 +169,10 @@ int main(int argc, char** argv) { } ota_io_init(za, state.is_retry); + // Initialize the cache_temp_source, last_command_file and stash_directory_base to their default + // locations. + CacheLocation::location().ResetLocations(); + std::string result; bool status = Evaluate(&state, root, &result); -- cgit v1.2.3