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
This commit is contained in:
Tianjie Xu 2018-02-27 15:56:11 -08:00
parent ac4818d6af
commit 3bbb20f557
11 changed files with 139 additions and 27 deletions

View file

@ -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<Value>& patch,
@ -404,7 +403,7 @@ int applypatch_check(const char* filename, const std::vector<std::string>& 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(), &copy_file) < 0) {
if (LoadFileContents(CacheLocation::location().cache_temp_source().c_str(), &copy_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;

View file

@ -33,6 +33,7 @@
#include <android-base/stringprintf.h>
#include "applypatch/applypatch.h"
#include "otautil/cache_location.h"
static int EliminateOpenFiles(std::set<std::string>* files) {
std::unique_ptr<DIR, decltype(&closedir)> d(opendir("/proc"), closedir);
@ -92,7 +93,7 @@ static std::set<std::string> 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;
}

View file

@ -34,12 +34,6 @@ struct FileContents {
std::vector<unsigned char> 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<size_t(const unsigned char*, size_t)>;
// applypatch.cpp

View file

@ -21,6 +21,7 @@ cc_library_static {
"SysUtil.cpp",
"DirUtil.cpp",
"ThermalUtil.cpp",
"cache_location.cpp",
"rangeset.cpp",
],

View file

@ -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;
}

View file

@ -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 <string>
#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_

View file

@ -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;

View file

@ -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');

View file

@ -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<std::string, RangeSet> 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;

View file

@ -19,7 +19,6 @@
#include <string>
extern std::string last_command_file;
void RegisterBlockImageFunctions();
#endif

View file

@ -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);