From 7934985e0cac4a3849418af3b8c9671f4d61078a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 24 Jul 2017 20:30:29 -0700 Subject: otautil: Delete dirUnlinkHierarchy(). This function has become obsolete since we've removed file-based OTA support (it was needed by 'delete_recursive' edify function earlier). Test: mmma -j bootable/recovery Test: Code search shows no active user of the function. Change-Id: If6faaa759d4c849b79acba4e6adb82baadc89f7a --- otautil/DirUtil.cpp | 56 ----------------------------------------------------- otautil/DirUtil.h | 13 ------------- 2 files changed, 69 deletions(-) (limited to 'otautil') diff --git a/otautil/DirUtil.cpp b/otautil/DirUtil.cpp index e08e360c0..ad344dedf 100644 --- a/otautil/DirUtil.cpp +++ b/otautil/DirUtil.cpp @@ -160,59 +160,3 @@ dirCreateHierarchy(const char *path, int mode, } return 0; } - -int -dirUnlinkHierarchy(const char *path) -{ - struct stat st; - DIR *dir; - struct dirent *de; - int fail = 0; - - /* is it a file or directory? */ - if (lstat(path, &st) < 0) { - return -1; - } - - /* a file, so unlink it */ - if (!S_ISDIR(st.st_mode)) { - return unlink(path); - } - - /* a directory, so open handle */ - dir = opendir(path); - if (dir == NULL) { - return -1; - } - - /* recurse over components */ - errno = 0; - while ((de = readdir(dir)) != NULL) { - //TODO: don't blow the stack - char dn[PATH_MAX]; - if (!strcmp(de->d_name, "..") || !strcmp(de->d_name, ".")) { - continue; - } - snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (dirUnlinkHierarchy(dn) < 0) { - fail = 1; - break; - } - errno = 0; - } - /* in case readdir or unlink_recursive failed */ - if (fail || errno < 0) { - int save = errno; - closedir(dir); - errno = save; - return -1; - } - - /* close directory handle */ - if (closedir(dir) < 0) { - return -1; - } - - /* delete target directory */ - return rmdir(path); -} diff --git a/otautil/DirUtil.h b/otautil/DirUtil.h index 85b83c387..beecc1081 100644 --- a/otautil/DirUtil.h +++ b/otautil/DirUtil.h @@ -17,13 +17,8 @@ #ifndef MINZIP_DIRUTIL_H_ #define MINZIP_DIRUTIL_H_ -#include #include -#ifdef __cplusplus -extern "C" { -#endif - struct selabel_handle; /* Like "mkdir -p", try to guarantee that all directories @@ -43,12 +38,4 @@ int dirCreateHierarchy(const char *path, int mode, const struct utimbuf *timestamp, bool stripFileName, struct selabel_handle* sehnd); -/* rm -rf - */ -int dirUnlinkHierarchy(const char *path); - -#ifdef __cplusplus -} -#endif - #endif // MINZIP_DIRUTIL_H_ -- cgit v1.2.3 From ac3d1edca0ea91a192c3a9d52efbc439702e9cae Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sun, 23 Jul 2017 00:01:02 -0700 Subject: otautil: Clean up dirCreateHierarchy(). - Changed to std::string based implementation (mostly moved from the former make_parents() in updater/install.cpp); - Removed the timestamp parameter, which is only neeed by file-based OTA; - Changed the type of mode from int to mode_t; - Renamed dirCreateHierarchy() to mkdir_recursively(). Test: recovery_unit_test passes. Test: No external user of dirCreateHierarchy() in code search. Change-Id: I71f8c4b29bab625513bbc3af6d0d1ecdc3a2719a --- otautil/DirUtil.cpp | 200 ++++++++++++++++++++-------------------------------- otautil/DirUtil.h | 38 +++++----- 2 files changed, 95 insertions(+), 143 deletions(-) (limited to 'otautil') diff --git a/otautil/DirUtil.cpp b/otautil/DirUtil.cpp index ad344dedf..fffc82219 100644 --- a/otautil/DirUtil.cpp +++ b/otautil/DirUtil.cpp @@ -16,147 +16,101 @@ #include "DirUtil.h" +#include +#include #include -#include -#include -#include #include +#include #include -#include -#include -#include #include #include #include -typedef enum { DMISSING, DDIR, DILLEGAL } DirStatus; - -static DirStatus -getPathDirStatus(const char *path) -{ - struct stat st; - int err; +enum class DirStatus { DMISSING, DDIR, DILLEGAL }; - err = stat(path, &st); - if (err == 0) { - /* Something's there; make sure it's a directory. - */ - if (S_ISDIR(st.st_mode)) { - return DDIR; - } - errno = ENOTDIR; - return DILLEGAL; - } else if (errno != ENOENT) { - /* Something went wrong, or something in the path - * is bad. Can't do anything in this situation. - */ - return DILLEGAL; +static DirStatus dir_status(const std::string& path) { + struct stat sb; + if (stat(path.c_str(), &sb) == 0) { + // Something's there; make sure it's a directory. + if (S_ISDIR(sb.st_mode)) { + return DirStatus::DDIR; } - return DMISSING; + errno = ENOTDIR; + return DirStatus::DILLEGAL; + } else if (errno != ENOENT) { + // Something went wrong, or something in the path is bad. Can't do anything in this situation. + return DirStatus::DILLEGAL; + } + return DirStatus::DMISSING; } -int -dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName, - struct selabel_handle *sehnd) -{ - DirStatus ds; - - /* Check for an empty string before we bother - * making any syscalls. - */ - if (path[0] == '\0') { - errno = ENOENT; - return -1; +int mkdir_recursively(const std::string& input_path, mode_t mode, bool strip_filename, + const selabel_handle* sehnd) { + // Check for an empty string before we bother making any syscalls. + if (input_path.empty()) { + errno = ENOENT; + return -1; + } + + // Allocate a path that we can modify; stick a slash on the end to make things easier. + std::string path = input_path; + if (strip_filename) { + // Strip everything after the last slash. + size_t pos = path.rfind('/'); + if (pos == std::string::npos) { + errno = ENOENT; + return -1; } - // Allocate a path that we can modify; stick a slash on - // the end to make things easier. - std::string cpath = path; - if (stripFileName) { - // Strip everything after the last slash. - size_t pos = cpath.rfind('/'); - if (pos == std::string::npos) { - errno = ENOENT; - return -1; - } - cpath.resize(pos + 1); - } else { - // Make sure that the path ends in a slash. - cpath.push_back('/'); + path.resize(pos + 1); + } else { + // Make sure that the path ends in a slash. + path.push_back('/'); + } + + // See if it already exists. + DirStatus ds = dir_status(path); + if (ds == DirStatus::DDIR) { + return 0; + } else if (ds == DirStatus::DILLEGAL) { + return -1; + } + + // Walk up the path from the root and make each level. + size_t prev_end = 0; + while (prev_end < path.size()) { + size_t next_end = path.find('/', prev_end + 1); + if (next_end == std::string::npos) { + break; } - - /* See if it already exists. - */ - ds = getPathDirStatus(cpath.c_str()); - if (ds == DDIR) { - return 0; - } else if (ds == DILLEGAL) { + std::string dir_path = path.substr(0, next_end); + // Check this part of the path and make a new directory if necessary. + switch (dir_status(dir_path)) { + case DirStatus::DILLEGAL: + // Could happen if some other process/thread is messing with the filesystem. return -1; - } - - /* Walk up the path from the root and make each level. - * If a directory already exists, no big deal. - */ - const char *path_start = &cpath[0]; - char *p = &cpath[0]; - while (*p != '\0') { - /* Skip any slashes, watching out for the end of the string. - */ - while (*p != '\0' && *p == '/') { - p++; - } - if (*p == '\0') { - break; + case DirStatus::DMISSING: { + char* secontext = nullptr; + if (sehnd) { + selabel_lookup(const_cast(sehnd), &secontext, dir_path.c_str(), mode); + setfscreatecon(secontext); } - - /* Find the end of the next path component. - * We know that we'll see a slash before the NUL, - * because we added it, above. - */ - while (*p != '/') { - p++; + int err = mkdir(dir_path.c_str(), mode); + if (secontext) { + freecon(secontext); + setfscreatecon(nullptr); } - *p = '\0'; - - /* Check this part of the path and make a new directory - * if necessary. - */ - ds = getPathDirStatus(path_start); - if (ds == DILLEGAL) { - /* Could happen if some other process/thread is - * messing with the filesystem. - */ - return -1; - } else if (ds == DMISSING) { - int err; - - char *secontext = NULL; - - if (sehnd) { - selabel_lookup(sehnd, &secontext, path_start, mode); - setfscreatecon(secontext); - } - - err = mkdir(path_start, mode); - - if (secontext) { - freecon(secontext); - setfscreatecon(NULL); - } - - if (err != 0) { - return -1; - } - if (timestamp != NULL && utime(path_start, timestamp)) { - return -1; - } + if (err != 0) { + return -1; } - // else, this directory already exists. - - // Repair the path and continue. - *p = '/'; + break; + } + default: + // Already exists. + break; } - return 0; + prev_end = next_end; + } + return 0; } diff --git a/otautil/DirUtil.h b/otautil/DirUtil.h index beecc1081..85d6c16d1 100644 --- a/otautil/DirUtil.h +++ b/otautil/DirUtil.h @@ -14,28 +14,26 @@ * limitations under the License. */ -#ifndef MINZIP_DIRUTIL_H_ -#define MINZIP_DIRUTIL_H_ +#ifndef OTAUTIL_DIRUTIL_H_ +#define OTAUTIL_DIRUTIL_H_ -#include +#include // mode_t + +#include struct selabel_handle; -/* Like "mkdir -p", try to guarantee that all directories - * specified in path are present, creating as many directories - * as necessary. The specified mode is passed to all mkdir - * calls; no modifications are made to umask. - * - * If stripFileName is set, everything after the final '/' - * is stripped before creating the directory hierarchy. - * - * If timestamp is non-NULL, new directories will be timestamped accordingly. - * - * Returns 0 on success; returns -1 (and sets errno) on failure - * (usually if some element of path is not a directory). - */ -int dirCreateHierarchy(const char *path, int mode, - const struct utimbuf *timestamp, bool stripFileName, - struct selabel_handle* sehnd); +// Like "mkdir -p", try to guarantee that all directories specified in path are present, creating as +// many directories as necessary. The specified mode is passed to all mkdir calls; no modifications +// are made to umask. +// +// If strip_filename is set, everything after the final '/' is stripped before creating the +// directory +// hierarchy. +// +// Returns 0 on success; returns -1 (and sets errno) on failure (usually if some element of path is +// not a directory). +int mkdir_recursively(const std::string& path, mode_t mode, bool strip_filename, + const struct selabel_handle* sehnd); -#endif // MINZIP_DIRUTIL_H_ +#endif // OTAUTIL_DIRUTIL_H_ -- cgit v1.2.3 From cfe53c2c018eaac7991faa98b144543c8fcd174d Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 3 Oct 2017 14:37:21 -0700 Subject: otautil: Export headers. Test: mmma bootable/recovery Change-Id: Ic01b68e2a394d578fc9fc09da2dabe9061b98122 --- otautil/Android.bp | 4 +++ otautil/DirUtil.cpp | 2 +- otautil/DirUtil.h | 39 -------------------------- otautil/SysUtil.cpp | 2 +- otautil/SysUtil.h | 53 ----------------------------------- otautil/ThermalUtil.cpp | 4 +-- otautil/ThermalUtil.h | 24 ---------------- otautil/include/otautil/DirUtil.h | 39 ++++++++++++++++++++++++++ otautil/include/otautil/SysUtil.h | 53 +++++++++++++++++++++++++++++++++++ otautil/include/otautil/ThermalUtil.h | 24 ++++++++++++++++ 10 files changed, 124 insertions(+), 120 deletions(-) delete mode 100644 otautil/DirUtil.h delete mode 100644 otautil/SysUtil.h delete mode 100644 otautil/ThermalUtil.h create mode 100644 otautil/include/otautil/DirUtil.h create mode 100644 otautil/include/otautil/SysUtil.h create mode 100644 otautil/include/otautil/ThermalUtil.h (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index a2eaa0402..9cde7baa7 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -30,4 +30,8 @@ cc_library_static { "-Werror", "-Wall", ], + + export_include_dirs: [ + "include", + ], } diff --git a/otautil/DirUtil.cpp b/otautil/DirUtil.cpp index fffc82219..61c832813 100644 --- a/otautil/DirUtil.cpp +++ b/otautil/DirUtil.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "DirUtil.h" +#include "otautil/DirUtil.h" #include #include diff --git a/otautil/DirUtil.h b/otautil/DirUtil.h deleted file mode 100644 index 85d6c16d1..000000000 --- a/otautil/DirUtil.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2007 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_DIRUTIL_H_ -#define OTAUTIL_DIRUTIL_H_ - -#include // mode_t - -#include - -struct selabel_handle; - -// Like "mkdir -p", try to guarantee that all directories specified in path are present, creating as -// many directories as necessary. The specified mode is passed to all mkdir calls; no modifications -// are made to umask. -// -// If strip_filename is set, everything after the final '/' is stripped before creating the -// directory -// hierarchy. -// -// Returns 0 on success; returns -1 (and sets errno) on failure (usually if some element of path is -// not a directory). -int mkdir_recursively(const std::string& path, mode_t mode, bool strip_filename, - const struct selabel_handle* sehnd); - -#endif // OTAUTIL_DIRUTIL_H_ diff --git a/otautil/SysUtil.cpp b/otautil/SysUtil.cpp index dfa215073..d54a824d2 100644 --- a/otautil/SysUtil.cpp +++ b/otautil/SysUtil.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "SysUtil.h" +#include "otautil/SysUtil.h" #include #include // SIZE_MAX diff --git a/otautil/SysUtil.h b/otautil/SysUtil.h deleted file mode 100644 index 52f6d20a7..000000000 --- a/otautil/SysUtil.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2006 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_SYSUTIL -#define _OTAUTIL_SYSUTIL - -#include - -#include -#include - -/* - * Use this to keep track of mapped segments. - */ -class MemMapping { - public: - ~MemMapping(); - // Map a file into a private, read-only memory segment. If 'filename' begins with an '@' - // character, it is a map of blocks to be mapped, otherwise it is treated as an ordinary file. - bool MapFile(const std::string& filename); - size_t ranges() const { - return ranges_.size(); - }; - - unsigned char* addr; // start of data - size_t length; // length of data - - private: - struct MappedRange { - void* addr; - size_t length; - }; - - bool MapBlockFile(const std::string& filename); - bool MapFD(int fd); - - std::vector ranges_; -}; - -#endif // _OTAUTIL_SYSUTIL diff --git a/otautil/ThermalUtil.cpp b/otautil/ThermalUtil.cpp index 13d36432a..5d9bd45c0 100644 --- a/otautil/ThermalUtil.cpp +++ b/otautil/ThermalUtil.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "ThermalUtil.h" +#include "otautil/ThermalUtil.h" #include #include @@ -77,4 +77,4 @@ int GetMaxValueFromThermalZone() { } LOG(INFO) << "current maximum temperature: " << max_temperature; return max_temperature; -} \ No newline at end of file +} diff --git a/otautil/ThermalUtil.h b/otautil/ThermalUtil.h deleted file mode 100644 index 43ab55940..000000000 --- a/otautil/ThermalUtil.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef OTAUTIL_THERMALUTIL_H -#define OTAUTIL_THERMALUTIL_H - -// We can find the temperature reported by all sensors in /sys/class/thermal/thermal_zone*/temp. -// Their values are in millidegree Celsius; and we will log the maximum one. -int GetMaxValueFromThermalZone(); - -#endif // OTAUTIL_THERMALUTIL_H diff --git a/otautil/include/otautil/DirUtil.h b/otautil/include/otautil/DirUtil.h new file mode 100644 index 000000000..85d6c16d1 --- /dev/null +++ b/otautil/include/otautil/DirUtil.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2007 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_DIRUTIL_H_ +#define OTAUTIL_DIRUTIL_H_ + +#include // mode_t + +#include + +struct selabel_handle; + +// Like "mkdir -p", try to guarantee that all directories specified in path are present, creating as +// many directories as necessary. The specified mode is passed to all mkdir calls; no modifications +// are made to umask. +// +// If strip_filename is set, everything after the final '/' is stripped before creating the +// directory +// hierarchy. +// +// Returns 0 on success; returns -1 (and sets errno) on failure (usually if some element of path is +// not a directory). +int mkdir_recursively(const std::string& path, mode_t mode, bool strip_filename, + const struct selabel_handle* sehnd); + +#endif // OTAUTIL_DIRUTIL_H_ diff --git a/otautil/include/otautil/SysUtil.h b/otautil/include/otautil/SysUtil.h new file mode 100644 index 000000000..52f6d20a7 --- /dev/null +++ b/otautil/include/otautil/SysUtil.h @@ -0,0 +1,53 @@ +/* + * Copyright 2006 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_SYSUTIL +#define _OTAUTIL_SYSUTIL + +#include + +#include +#include + +/* + * Use this to keep track of mapped segments. + */ +class MemMapping { + public: + ~MemMapping(); + // Map a file into a private, read-only memory segment. If 'filename' begins with an '@' + // character, it is a map of blocks to be mapped, otherwise it is treated as an ordinary file. + bool MapFile(const std::string& filename); + size_t ranges() const { + return ranges_.size(); + }; + + unsigned char* addr; // start of data + size_t length; // length of data + + private: + struct MappedRange { + void* addr; + size_t length; + }; + + bool MapBlockFile(const std::string& filename); + bool MapFD(int fd); + + std::vector ranges_; +}; + +#endif // _OTAUTIL_SYSUTIL diff --git a/otautil/include/otautil/ThermalUtil.h b/otautil/include/otautil/ThermalUtil.h new file mode 100644 index 000000000..43ab55940 --- /dev/null +++ b/otautil/include/otautil/ThermalUtil.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OTAUTIL_THERMALUTIL_H +#define OTAUTIL_THERMALUTIL_H + +// We can find the temperature reported by all sensors in /sys/class/thermal/thermal_zone*/temp. +// Their values are in millidegree Celsius; and we will log the maximum one. +int GetMaxValueFromThermalZone(); + +#endif // OTAUTIL_THERMALUTIL_H -- cgit v1.2.3 From 623fe7e701d5d0fb17082d1ced14498af1b44e5b Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Mon, 2 Oct 2017 16:28:06 -0700 Subject: Move error_code.h into otautil. This way it stops requiring relative path ".." in LOCAL_C_INCLUDES (uncrypt and edify). Soong doesn't accept non-local ".." in "local_include_dirs". Test: mmma bootable/recovery Change-Id: Ia4649789cef2aaeb2785483660e9ea5a8b389c62 --- otautil/Android.bp | 2 + otautil/include/otautil/error_code.h | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 otautil/include/otautil/error_code.h (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index 9cde7baa7..5905ba649 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -15,6 +15,8 @@ cc_library_static { name: "libotautil", + host_supported: true, + srcs: [ "SysUtil.cpp", "DirUtil.cpp", diff --git a/otautil/include/otautil/error_code.h b/otautil/include/otautil/error_code.h new file mode 100644 index 000000000..943c7622d --- /dev/null +++ b/otautil/include/otautil/error_code.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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 _ERROR_CODE_H_ +#define _ERROR_CODE_H_ + +enum ErrorCode { + kNoError = -1, + kLowBattery = 20, + kZipVerificationFailure, + kZipOpenFailure, + kBootreasonInBlacklist, + kPackageCompatibilityFailure, + kScriptExecutionFailure, + kMapFileFailure, + kForkUpdateBinaryFailure, + kUpdateBinaryCommandFailure, +}; + +enum CauseCode { + kNoCause = -1, + kArgsParsingFailure = 100, + kStashCreationFailure, + kFileOpenFailure, + kLseekFailure, + kFreadFailure, + kFwriteFailure, + kFsyncFailure, + kLibfecFailure, + kFileGetPropFailure, + kFileRenameFailure, + kSymlinkFailure, + kSetMetadataFailure, + kTune2FsFailure, + kRebootFailure, + kPackageExtractFileFailure, + kPatchApplicationFailure, + kVendorFailure = 200 +}; + +enum UncryptErrorCode { + kUncryptNoError = -1, + kUncryptErrorPlaceholder = 50, + kUncryptTimeoutError = 100, + kUncryptFileRemoveError, + kUncryptFileOpenError, + kUncryptSocketOpenError, + kUncryptSocketWriteError, + kUncryptSocketListenError, + kUncryptSocketAcceptError, + kUncryptFstabReadError, + kUncryptFileStatError, + kUncryptBlockOpenError, + kUncryptIoctlError, + kUncryptReadError, + kUncryptWriteError, + kUncryptFileSyncError, + kUncryptFileCloseError, + kUncryptFileRenameError, + kUncryptPackageMissingError, + kUncryptRealpathFindError, + kUncryptBlockDeviceFindError, +}; + +#endif // _ERROR_CODE_H_ -- cgit v1.2.3 From 26436d6d6010d5323349af7e119ff8f34f85c40c Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Thu, 5 Oct 2017 17:16:31 +0000 Subject: Revert "Move error_code.h into otautil." This reverts commit 623fe7e701d5d0fb17082d1ced14498af1b44e5b. Reason for revert: Need to address device-specific modules. Change-Id: Ib7a4191e7f193dfff49b02d3de76dda856800251 --- otautil/Android.bp | 2 - otautil/include/otautil/error_code.h | 78 ------------------------------------ 2 files changed, 80 deletions(-) delete mode 100644 otautil/include/otautil/error_code.h (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index 5905ba649..9cde7baa7 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -15,8 +15,6 @@ cc_library_static { name: "libotautil", - host_supported: true, - srcs: [ "SysUtil.cpp", "DirUtil.cpp", diff --git a/otautil/include/otautil/error_code.h b/otautil/include/otautil/error_code.h deleted file mode 100644 index 943c7622d..000000000 --- a/otautil/include/otautil/error_code.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2016 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 _ERROR_CODE_H_ -#define _ERROR_CODE_H_ - -enum ErrorCode { - kNoError = -1, - kLowBattery = 20, - kZipVerificationFailure, - kZipOpenFailure, - kBootreasonInBlacklist, - kPackageCompatibilityFailure, - kScriptExecutionFailure, - kMapFileFailure, - kForkUpdateBinaryFailure, - kUpdateBinaryCommandFailure, -}; - -enum CauseCode { - kNoCause = -1, - kArgsParsingFailure = 100, - kStashCreationFailure, - kFileOpenFailure, - kLseekFailure, - kFreadFailure, - kFwriteFailure, - kFsyncFailure, - kLibfecFailure, - kFileGetPropFailure, - kFileRenameFailure, - kSymlinkFailure, - kSetMetadataFailure, - kTune2FsFailure, - kRebootFailure, - kPackageExtractFileFailure, - kPatchApplicationFailure, - kVendorFailure = 200 -}; - -enum UncryptErrorCode { - kUncryptNoError = -1, - kUncryptErrorPlaceholder = 50, - kUncryptTimeoutError = 100, - kUncryptFileRemoveError, - kUncryptFileOpenError, - kUncryptSocketOpenError, - kUncryptSocketWriteError, - kUncryptSocketListenError, - kUncryptSocketAcceptError, - kUncryptFstabReadError, - kUncryptFileStatError, - kUncryptBlockOpenError, - kUncryptIoctlError, - kUncryptReadError, - kUncryptWriteError, - kUncryptFileSyncError, - kUncryptFileCloseError, - kUncryptFileRenameError, - kUncryptPackageMissingError, - kUncryptRealpathFindError, - kUncryptBlockDeviceFindError, -}; - -#endif // _ERROR_CODE_H_ -- cgit v1.2.3 From 1fc5bf353a8719d16fd9ba29a661d211bad4038f Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 6 Oct 2017 07:43:41 -0700 Subject: Revert "Revert "Move error_code.h into otautil."" This reverts commit 26436d6d6010d5323349af7e119ff8f34f85c40c to re-land "Move error_code.h into otautil.". This way it stops requiring relative path ".." in LOCAL_C_INCLUDES (uncrypt and edify). Soong doesn't accept non-local ".." in "local_include_dirs". This CL needs to land with device-specific module changes (e.g. adding the dependency on libotautil). Test: lunch aosp_{angler,bullhead,dragon,fugu,sailfish}-userdebug; mmma bootable/recovery Change-Id: If193241801af2dae73eccd31ce57cd2b81c9fd96 --- otautil/Android.bp | 2 + otautil/include/otautil/error_code.h | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 otautil/include/otautil/error_code.h (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index 9cde7baa7..5905ba649 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -15,6 +15,8 @@ cc_library_static { name: "libotautil", + host_supported: true, + srcs: [ "SysUtil.cpp", "DirUtil.cpp", diff --git a/otautil/include/otautil/error_code.h b/otautil/include/otautil/error_code.h new file mode 100644 index 000000000..b0ff42d8d --- /dev/null +++ b/otautil/include/otautil/error_code.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2016 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 _ERROR_CODE_H_ +#define _ERROR_CODE_H_ + +enum ErrorCode : int { + kNoError = -1, + kLowBattery = 20, + kZipVerificationFailure, + kZipOpenFailure, + kBootreasonInBlacklist, + kPackageCompatibilityFailure, + kScriptExecutionFailure, + kMapFileFailure, + kForkUpdateBinaryFailure, + kUpdateBinaryCommandFailure, +}; + +enum CauseCode : int { + kNoCause = -1, + kArgsParsingFailure = 100, + kStashCreationFailure, + kFileOpenFailure, + kLseekFailure, + kFreadFailure, + kFwriteFailure, + kFsyncFailure, + kLibfecFailure, + kFileGetPropFailure, + kFileRenameFailure, + kSymlinkFailure, + kSetMetadataFailure, + kTune2FsFailure, + kRebootFailure, + kPackageExtractFileFailure, + kPatchApplicationFailure, + kVendorFailure = 200 +}; + +enum UncryptErrorCode : int { + kUncryptNoError = -1, + kUncryptErrorPlaceholder = 50, + kUncryptTimeoutError = 100, + kUncryptFileRemoveError, + kUncryptFileOpenError, + kUncryptSocketOpenError, + kUncryptSocketWriteError, + kUncryptSocketListenError, + kUncryptSocketAcceptError, + kUncryptFstabReadError, + kUncryptFileStatError, + kUncryptBlockOpenError, + kUncryptIoctlError, + kUncryptReadError, + kUncryptWriteError, + kUncryptFileSyncError, + kUncryptFileCloseError, + kUncryptFileRenameError, + kUncryptPackageMissingError, + kUncryptRealpathFindError, + kUncryptBlockDeviceFindError, +}; + +#endif // _ERROR_CODE_H_ -- cgit v1.2.3 From c13d2ec7726bae1a6ec0d29c4b4ed54ac46149a1 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 10 Oct 2017 10:56:09 -0700 Subject: otautil: Fix mac build. bootable/recovery/otautil/SysUtil.cpp:103:19: error: use of undeclared identifier 'mmap64'; did you mean 'mmap'? void* reserve = mmap64(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); ^~~~~~ Test: mmma bootable/recovery Change-Id: I22d7dc4d994069201e5a633cec21421e2c4182fa --- otautil/Android.bp | 1 + otautil/SysUtil.cpp | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index 5905ba649..659fefada 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -29,6 +29,7 @@ cc_library_static { ], cflags: [ + "-D_FILE_OFFSET_BITS=64", "-Werror", "-Wall", ], diff --git a/otautil/SysUtil.cpp b/otautil/SysUtil.cpp index d54a824d2..0655c4778 100644 --- a/otautil/SysUtil.cpp +++ b/otautil/SysUtil.cpp @@ -100,7 +100,7 @@ bool MemMapping::MapBlockFile(const std::string& filename) { } // Reserve enough contiguous address space for the whole file. - void* reserve = mmap64(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); + void* reserve = mmap(nullptr, blocks * blksize, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); if (reserve == MAP_FAILED) { PLOG(ERROR) << "failed to reserve address space"; return false; @@ -135,8 +135,8 @@ bool MemMapping::MapBlockFile(const std::string& filename) { break; } - void* range_start = mmap64(next, range_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, - static_cast(start) * blksize); + void* range_start = mmap(next, range_size, PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, + static_cast(start) * blksize); if (range_start == MAP_FAILED) { PLOG(ERROR) << "failed to map range " << i << ": " << line; success = false; -- cgit v1.2.3 From 09e468f84cc245fba61d69165b4af8f1ec4cdfd5 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 29 Sep 2017 14:39:33 -0700 Subject: Move rangeset.h and print_sha1.h into otautil. Also drop the "bootable/recovery" path in LOCAL_C_INCLUDES from applypatch modules. Test: lunch aosp_{angler,bullhead,fugu,dragon,sailfish}-userdebug; mmma bootable/recovery Change-Id: Idd602a796894f971ee4f8fa3eafe36c42d9de986 --- otautil/include/otautil/print_sha1.h | 47 ++++++ otautil/include/otautil/rangeset.h | 278 +++++++++++++++++++++++++++++++++++ 2 files changed, 325 insertions(+) create mode 100644 otautil/include/otautil/print_sha1.h create mode 100644 otautil/include/otautil/rangeset.h (limited to 'otautil') diff --git a/otautil/include/otautil/print_sha1.h b/otautil/include/otautil/print_sha1.h new file mode 100644 index 000000000..03a8d292a --- /dev/null +++ b/otautil/include/otautil/print_sha1.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 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 RECOVERY_PRINT_SHA1_H +#define RECOVERY_PRINT_SHA1_H + +#include +#include + +#include + +static std::string print_sha1(const uint8_t* sha1, size_t len) { + const char* hex = "0123456789abcdef"; + std::string result = ""; + for (size_t i = 0; i < len; ++i) { + result.push_back(hex[(sha1[i] >> 4) & 0xf]); + result.push_back(hex[sha1[i] & 0xf]); + } + return result; +} + +[[maybe_unused]] static std::string print_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) { + return print_sha1(sha1, SHA_DIGEST_LENGTH); +} + +[[maybe_unused]] static std::string short_sha1(const uint8_t sha1[SHA_DIGEST_LENGTH]) { + return print_sha1(sha1, 4); +} + +[[maybe_unused]] static std::string print_hex(const uint8_t* bytes, size_t len) { + return print_sha1(bytes, len); +} + +#endif // RECOVERY_PRINT_SHA1_H diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h new file mode 100644 index 000000000..f224a08be --- /dev/null +++ b/otautil/include/otautil/rangeset.h @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include +#include + +using Range = std::pair; + +class RangeSet { + public: + RangeSet() : blocks_(0) {} + + explicit RangeSet(std::vector&& pairs) { + CHECK_NE(pairs.size(), static_cast(0)) << "Invalid number of tokens"; + + // Sanity check the input. + size_t result = 0; + for (const auto& range : pairs) { + CHECK_LT(range.first, range.second) + << "Empty or negative range: " << range.first << ", " << range.second; + size_t sz = range.second - range.first; + CHECK_LE(result, SIZE_MAX - sz) << "RangeSet size overflow"; + result += sz; + } + + ranges_ = pairs; + blocks_ = result; + } + + static RangeSet Parse(const std::string& range_text) { + std::vector pieces = android::base::Split(range_text, ","); + CHECK_GE(pieces.size(), static_cast(3)) << "Invalid range text: " << range_text; + + size_t num; + CHECK(android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) + << "Failed to parse the number of tokens: " << range_text; + + CHECK_NE(num, static_cast(0)) << "Invalid number of tokens: " << range_text; + CHECK_EQ(num % 2, static_cast(0)) << "Number of tokens must be even: " << range_text; + CHECK_EQ(num, pieces.size() - 1) << "Mismatching number of tokens: " << range_text; + + std::vector pairs; + for (size_t i = 0; i < num; i += 2) { + size_t first; + CHECK(android::base::ParseUint(pieces[i + 1], &first, static_cast(INT_MAX))); + size_t second; + CHECK(android::base::ParseUint(pieces[i + 2], &second, static_cast(INT_MAX))); + + pairs.emplace_back(first, second); + } + + return RangeSet(std::move(pairs)); + } + + std::string ToString() const { + if (ranges_.empty()) { + return ""; + } + std::string result = std::to_string(ranges_.size() * 2); + for (const auto& r : ranges_) { + result += android::base::StringPrintf(",%zu,%zu", r.first, r.second); + } + + return result; + } + + // Get the block number for the i-th (starting from 0) block in the RangeSet. + size_t GetBlockNumber(size_t idx) const { + CHECK_LT(idx, blocks_) << "Out of bound index " << idx << " (total blocks: " << blocks_ << ")"; + + for (const auto& range : ranges_) { + if (idx < range.second - range.first) { + return range.first + idx; + } + idx -= (range.second - range.first); + } + + CHECK(false) << "Failed to find block number for index " << idx; + return 0; // Unreachable, but to make compiler happy. + } + + // RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" + // and "5,7" are not overlapped. + bool Overlaps(const RangeSet& other) const { + for (const auto& range : ranges_) { + size_t start = range.first; + size_t end = range.second; + for (const auto& other_range : other.ranges_) { + size_t other_start = other_range.first; + size_t other_end = other_range.second; + // [start, end) vs [other_start, other_end) + if (!(other_start >= end || start >= other_end)) { + return true; + } + } + } + return false; + } + + // size() gives the number of Range's in this RangeSet. + size_t size() const { + return ranges_.size(); + } + + // blocks() gives the number of all blocks in this RangeSet. + size_t blocks() const { + return blocks_; + } + + // We provide const iterators only. + std::vector::const_iterator cbegin() const { + return ranges_.cbegin(); + } + + std::vector::const_iterator cend() const { + return ranges_.cend(); + } + + // Need to provide begin()/end() since range-based loop expects begin()/end(). + std::vector::const_iterator begin() const { + return ranges_.cbegin(); + } + + std::vector::const_iterator end() const { + return ranges_.cend(); + } + + // Reverse const iterators for MoveRange(). + std::vector::const_reverse_iterator crbegin() const { + return ranges_.crbegin(); + } + + std::vector::const_reverse_iterator crend() const { + return ranges_.crend(); + } + + const Range& operator[](size_t i) const { + return ranges_[i]; + } + + bool operator==(const RangeSet& other) const { + // The orders of Range's matter. "4,1,5,8,10" != "4,8,10,1,5". + return (ranges_ == other.ranges_); + } + + bool operator!=(const RangeSet& other) const { + return ranges_ != other.ranges_; + } + + protected: + // Actual limit for each value and the total number are both INT_MAX. + std::vector ranges_; + size_t blocks_; +}; + +static constexpr size_t kBlockSize = 4096; + +// The class is a sorted version of a RangeSet; and it's useful in imgdiff to split the input +// files when we're handling large zip files. Specifically, we can treat the input file as a +// continuous RangeSet (i.e. RangeSet("0-99") for a 100 blocks file); and break it down into +// several smaller chunks based on the zip entries. + +// For example, [source: 0-99] can be split into +// [split_src1: 10-29]; [split_src2: 40-49, 60-69]; [split_src3: 70-89] +// Here "10-29" simply means block 10th to block 29th with respect to the original input file. +// Also, note that the split sources should be mutual exclusive, but they don't need to cover +// every block in the original source. +class SortedRangeSet : public RangeSet { + public: + SortedRangeSet() {} + + // Ranges in the the set should be mutually exclusive; and they're sorted by the start block. + explicit SortedRangeSet(std::vector&& pairs) : RangeSet(std::move(pairs)) { + std::sort(ranges_.begin(), ranges_.end()); + } + + void Insert(const Range& to_insert) { + SortedRangeSet rs({ to_insert }); + Insert(rs); + } + + // Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges. + void Insert(const SortedRangeSet& rs) { + if (rs.size() == 0) { + return; + } + // Merge and sort the two RangeSets. + std::vector temp = std::move(ranges_); + std::copy(rs.begin(), rs.end(), std::back_inserter(temp)); + std::sort(temp.begin(), temp.end()); + + Clear(); + // Trim overlaps and insert the result back to ranges_. + Range to_insert = temp.front(); + for (auto it = temp.cbegin() + 1; it != temp.cend(); it++) { + if (it->first <= to_insert.second) { + to_insert.second = std::max(to_insert.second, it->second); + } else { + ranges_.push_back(to_insert); + blocks_ += (to_insert.second - to_insert.first); + to_insert = *it; + } + } + ranges_.push_back(to_insert); + blocks_ += (to_insert.second - to_insert.first); + } + + void Clear() { + blocks_ = 0; + ranges_.clear(); + } + + using RangeSet::Overlaps; + bool Overlaps(size_t start, size_t len) const { + RangeSet rs({ { start / kBlockSize, (start + len - 1) / kBlockSize + 1 } }); + return Overlaps(rs); + } + + // Compute the block range the file occupies, and insert that range. + void Insert(size_t start, size_t len) { + Range to_insert{ start / kBlockSize, (start + len - 1) / kBlockSize + 1 }; + Insert(to_insert); + } + + // Given an offset of the file, checks if the corresponding block (by considering the file as + // 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset + // within this SortedRangeSet. + // + // For example, the 4106-th byte of a file is from block 1, assuming a block size of 4096-byte. + // The mapped offset within a SortedRangeSet("1-9 15-19") is 10. + // + // An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th + // item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10 + // + 10) in a range represented by this SortedRangeSet. + size_t GetOffsetInRangeSet(size_t old_offset) const { + size_t old_block_start = old_offset / kBlockSize; + size_t new_block_start = 0; + for (const auto& range : ranges_) { + // Find the index of old_block_start. + if (old_block_start >= range.second) { + new_block_start += (range.second - range.first); + } else if (old_block_start >= range.first) { + new_block_start += (old_block_start - range.first); + return (new_block_start * kBlockSize + old_offset % kBlockSize); + } else { + CHECK(false) << "block_start " << old_block_start + << " is missing between two ranges: " << this->ToString(); + return 0; + } + } + CHECK(false) << "block_start " << old_block_start + << " exceeds the limit of current RangeSet: " << this->ToString(); + return 0; + } +}; \ No newline at end of file -- cgit v1.2.3 From b9bffdffb944663c61fdbebcdedcf9b87fd2450e Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Wed, 11 Oct 2017 12:14:38 -0700 Subject: otautil: #include for TEMP_FAILURE_RETRY. Test: mmma bootable/recovery Change-Id: I5959303528c6f704f10ce153f6fcb2054ce35b1e --- otautil/SysUtil.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'otautil') diff --git a/otautil/SysUtil.cpp b/otautil/SysUtil.cpp index 0655c4778..48336ad07 100644 --- a/otautil/SysUtil.cpp +++ b/otautil/SysUtil.cpp @@ -16,6 +16,7 @@ #include "otautil/SysUtil.h" +#include // TEMP_FAILURE_RETRY #include #include // SIZE_MAX #include -- cgit v1.2.3 From 45685820029fb191fe8509418df91a049227ea3a Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Fri, 13 Oct 2017 14:54:12 -0700 Subject: otautil: Move RangeSet implementation into rangeset.cpp. Since it has grown much larger, users of the header shouldn't compile and carry their full copies. Also add missing header includes in imgdiff.cpp and imgdiff_test.cpp. Test: mmma bootable/recovery Test: recovery_unit_test; recovery_component_test; recovery_host_test Change-Id: I88ca54171765e5606ab0d61580fbc1ada578fd7d --- otautil/Android.bp | 1 + otautil/include/otautil/rangeset.h | 166 +++--------------------------- otautil/rangeset.cpp | 200 +++++++++++++++++++++++++++++++++++++ 3 files changed, 216 insertions(+), 151 deletions(-) create mode 100644 otautil/rangeset.cpp (limited to 'otautil') diff --git a/otautil/Android.bp b/otautil/Android.bp index 659fefada..5efb12d60 100644 --- a/otautil/Android.bp +++ b/otautil/Android.bp @@ -21,6 +21,7 @@ cc_library_static { "SysUtil.cpp", "DirUtil.cpp", "ThermalUtil.cpp", + "rangeset.cpp", ], static_libs: [ diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h index f224a08be..c4234d181 100644 --- a/otautil/include/otautil/rangeset.h +++ b/otautil/include/otautil/rangeset.h @@ -22,103 +22,24 @@ #include #include -#include -#include -#include -#include - using Range = std::pair; class RangeSet { public: RangeSet() : blocks_(0) {} - explicit RangeSet(std::vector&& pairs) { - CHECK_NE(pairs.size(), static_cast(0)) << "Invalid number of tokens"; - - // Sanity check the input. - size_t result = 0; - for (const auto& range : pairs) { - CHECK_LT(range.first, range.second) - << "Empty or negative range: " << range.first << ", " << range.second; - size_t sz = range.second - range.first; - CHECK_LE(result, SIZE_MAX - sz) << "RangeSet size overflow"; - result += sz; - } - - ranges_ = pairs; - blocks_ = result; - } - - static RangeSet Parse(const std::string& range_text) { - std::vector pieces = android::base::Split(range_text, ","); - CHECK_GE(pieces.size(), static_cast(3)) << "Invalid range text: " << range_text; - - size_t num; - CHECK(android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) - << "Failed to parse the number of tokens: " << range_text; - - CHECK_NE(num, static_cast(0)) << "Invalid number of tokens: " << range_text; - CHECK_EQ(num % 2, static_cast(0)) << "Number of tokens must be even: " << range_text; - CHECK_EQ(num, pieces.size() - 1) << "Mismatching number of tokens: " << range_text; - - std::vector pairs; - for (size_t i = 0; i < num; i += 2) { - size_t first; - CHECK(android::base::ParseUint(pieces[i + 1], &first, static_cast(INT_MAX))); - size_t second; - CHECK(android::base::ParseUint(pieces[i + 2], &second, static_cast(INT_MAX))); + explicit RangeSet(std::vector&& pairs); - pairs.emplace_back(first, second); - } + static RangeSet Parse(const std::string& range_text); - return RangeSet(std::move(pairs)); - } - - std::string ToString() const { - if (ranges_.empty()) { - return ""; - } - std::string result = std::to_string(ranges_.size() * 2); - for (const auto& r : ranges_) { - result += android::base::StringPrintf(",%zu,%zu", r.first, r.second); - } - - return result; - } + std::string ToString() const; // Get the block number for the i-th (starting from 0) block in the RangeSet. - size_t GetBlockNumber(size_t idx) const { - CHECK_LT(idx, blocks_) << "Out of bound index " << idx << " (total blocks: " << blocks_ << ")"; - - for (const auto& range : ranges_) { - if (idx < range.second - range.first) { - return range.first + idx; - } - idx -= (range.second - range.first); - } - - CHECK(false) << "Failed to find block number for index " << idx; - return 0; // Unreachable, but to make compiler happy. - } + size_t GetBlockNumber(size_t idx) const; // RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" // and "5,7" are not overlapped. - bool Overlaps(const RangeSet& other) const { - for (const auto& range : ranges_) { - size_t start = range.first; - size_t end = range.second; - for (const auto& other_range : other.ranges_) { - size_t other_start = other_range.first; - size_t other_end = other_range.second; - // [start, end) vs [other_start, other_end) - if (!(other_start >= end || start >= other_end)) { - return true; - } - } - } - return false; - } + bool Overlaps(const RangeSet& other) const; // size() gives the number of Range's in this RangeSet. size_t size() const { @@ -176,8 +97,6 @@ class RangeSet { size_t blocks_; }; -static constexpr size_t kBlockSize = 4096; - // The class is a sorted version of a RangeSet; and it's useful in imgdiff to split the input // files when we're handling large zip files. Specifically, we can treat the input file as a // continuous RangeSet (i.e. RangeSet("0-99") for a 100 blocks file); and break it down into @@ -193,57 +112,21 @@ class SortedRangeSet : public RangeSet { SortedRangeSet() {} // Ranges in the the set should be mutually exclusive; and they're sorted by the start block. - explicit SortedRangeSet(std::vector&& pairs) : RangeSet(std::move(pairs)) { - std::sort(ranges_.begin(), ranges_.end()); - } + explicit SortedRangeSet(std::vector&& pairs); - void Insert(const Range& to_insert) { - SortedRangeSet rs({ to_insert }); - Insert(rs); - } + void Insert(const Range& to_insert); // Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges. - void Insert(const SortedRangeSet& rs) { - if (rs.size() == 0) { - return; - } - // Merge and sort the two RangeSets. - std::vector temp = std::move(ranges_); - std::copy(rs.begin(), rs.end(), std::back_inserter(temp)); - std::sort(temp.begin(), temp.end()); - - Clear(); - // Trim overlaps and insert the result back to ranges_. - Range to_insert = temp.front(); - for (auto it = temp.cbegin() + 1; it != temp.cend(); it++) { - if (it->first <= to_insert.second) { - to_insert.second = std::max(to_insert.second, it->second); - } else { - ranges_.push_back(to_insert); - blocks_ += (to_insert.second - to_insert.first); - to_insert = *it; - } - } - ranges_.push_back(to_insert); - blocks_ += (to_insert.second - to_insert.first); - } + void Insert(const SortedRangeSet& rs); - void Clear() { - blocks_ = 0; - ranges_.clear(); - } + // Compute the block range the file occupies, and insert that range. + void Insert(size_t start, size_t len); + + void Clear(); using RangeSet::Overlaps; - bool Overlaps(size_t start, size_t len) const { - RangeSet rs({ { start / kBlockSize, (start + len - 1) / kBlockSize + 1 } }); - return Overlaps(rs); - } - // Compute the block range the file occupies, and insert that range. - void Insert(size_t start, size_t len) { - Range to_insert{ start / kBlockSize, (start + len - 1) / kBlockSize + 1 }; - Insert(to_insert); - } + bool Overlaps(size_t start, size_t len) const; // Given an offset of the file, checks if the corresponding block (by considering the file as // 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset @@ -255,24 +138,5 @@ class SortedRangeSet : public RangeSet { // An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th // item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10 // + 10) in a range represented by this SortedRangeSet. - size_t GetOffsetInRangeSet(size_t old_offset) const { - size_t old_block_start = old_offset / kBlockSize; - size_t new_block_start = 0; - for (const auto& range : ranges_) { - // Find the index of old_block_start. - if (old_block_start >= range.second) { - new_block_start += (range.second - range.first); - } else if (old_block_start >= range.first) { - new_block_start += (old_block_start - range.first); - return (new_block_start * kBlockSize + old_offset % kBlockSize); - } else { - CHECK(false) << "block_start " << old_block_start - << " is missing between two ranges: " << this->ToString(); - return 0; - } - } - CHECK(false) << "block_start " << old_block_start - << " exceeds the limit of current RangeSet: " << this->ToString(); - return 0; - } -}; \ No newline at end of file + size_t GetOffsetInRangeSet(size_t old_offset) const; +}; diff --git a/otautil/rangeset.cpp b/otautil/rangeset.cpp new file mode 100644 index 000000000..a121a4efc --- /dev/null +++ b/otautil/rangeset.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otautil/rangeset.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include + +RangeSet::RangeSet(std::vector&& pairs) { + CHECK_NE(pairs.size(), static_cast(0)) << "Invalid number of tokens"; + + // Sanity check the input. + size_t result = 0; + for (const auto& range : pairs) { + CHECK_LT(range.first, range.second) << "Empty or negative range: " << range.first << ", " + << range.second; + size_t sz = range.second - range.first; + CHECK_LE(result, SIZE_MAX - sz) << "RangeSet size overflow"; + result += sz; + } + + ranges_ = pairs; + blocks_ = result; +} + +RangeSet RangeSet::Parse(const std::string& range_text) { + std::vector pieces = android::base::Split(range_text, ","); + CHECK_GE(pieces.size(), static_cast(3)) << "Invalid range text: " << range_text; + + size_t num; + CHECK(android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) + << "Failed to parse the number of tokens: " << range_text; + + CHECK_NE(num, static_cast(0)) << "Invalid number of tokens: " << range_text; + CHECK_EQ(num % 2, static_cast(0)) << "Number of tokens must be even: " << range_text; + CHECK_EQ(num, pieces.size() - 1) << "Mismatching number of tokens: " << range_text; + + std::vector pairs; + for (size_t i = 0; i < num; i += 2) { + size_t first; + CHECK(android::base::ParseUint(pieces[i + 1], &first, static_cast(INT_MAX))); + size_t second; + CHECK(android::base::ParseUint(pieces[i + 2], &second, static_cast(INT_MAX))); + + pairs.emplace_back(first, second); + } + + return RangeSet(std::move(pairs)); +} + +std::string RangeSet::ToString() const { + if (ranges_.empty()) { + return ""; + } + std::string result = std::to_string(ranges_.size() * 2); + for (const auto& r : ranges_) { + result += android::base::StringPrintf(",%zu,%zu", r.first, r.second); + } + + return result; +} + +// Get the block number for the i-th (starting from 0) block in the RangeSet. +size_t RangeSet::GetBlockNumber(size_t idx) const { + CHECK_LT(idx, blocks_) << "Out of bound index " << idx << " (total blocks: " << blocks_ << ")"; + + for (const auto& range : ranges_) { + if (idx < range.second - range.first) { + return range.first + idx; + } + idx -= (range.second - range.first); + } + + CHECK(false) << "Failed to find block number for index " << idx; + return 0; // Unreachable, but to make compiler happy. +} + +// RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" +// and "5,7" are not overlapped. +bool RangeSet::Overlaps(const RangeSet& other) const { + for (const auto& range : ranges_) { + size_t start = range.first; + size_t end = range.second; + for (const auto& other_range : other.ranges_) { + size_t other_start = other_range.first; + size_t other_end = other_range.second; + // [start, end) vs [other_start, other_end) + if (!(other_start >= end || start >= other_end)) { + return true; + } + } + } + return false; +} + +static constexpr size_t kBlockSize = 4096; + +// Ranges in the the set should be mutually exclusive; and they're sorted by the start block. +SortedRangeSet::SortedRangeSet(std::vector&& pairs) : RangeSet(std::move(pairs)) { + std::sort(ranges_.begin(), ranges_.end()); +} + +void SortedRangeSet::Insert(const Range& to_insert) { + SortedRangeSet rs({ to_insert }); + Insert(rs); +} + +// Insert the input SortedRangeSet; keep the ranges sorted and merge the overlap ranges. +void SortedRangeSet::Insert(const SortedRangeSet& rs) { + if (rs.size() == 0) { + return; + } + // Merge and sort the two RangeSets. + std::vector temp = std::move(ranges_); + std::copy(rs.begin(), rs.end(), std::back_inserter(temp)); + std::sort(temp.begin(), temp.end()); + + Clear(); + // Trim overlaps and insert the result back to ranges_. + Range to_insert = temp.front(); + for (auto it = temp.cbegin() + 1; it != temp.cend(); it++) { + if (it->first <= to_insert.second) { + to_insert.second = std::max(to_insert.second, it->second); + } else { + ranges_.push_back(to_insert); + blocks_ += (to_insert.second - to_insert.first); + to_insert = *it; + } + } + ranges_.push_back(to_insert); + blocks_ += (to_insert.second - to_insert.first); +} + +// Compute the block range the file occupies, and insert that range. +void SortedRangeSet::Insert(size_t start, size_t len) { + Range to_insert{ start / kBlockSize, (start + len - 1) / kBlockSize + 1 }; + Insert(to_insert); +} + +void SortedRangeSet::Clear() { + blocks_ = 0; + ranges_.clear(); +} + +bool SortedRangeSet::Overlaps(size_t start, size_t len) const { + RangeSet rs({ { start / kBlockSize, (start + len - 1) / kBlockSize + 1 } }); + return Overlaps(rs); +} + +// Given an offset of the file, checks if the corresponding block (by considering the file as +// 0-based continuous block ranges) is covered by the SortedRangeSet. If so, returns the offset +// within this SortedRangeSet. +// +// For example, the 4106-th byte of a file is from block 1, assuming a block size of 4096-byte. +// The mapped offset within a SortedRangeSet("1-9 15-19") is 10. +// +// An offset of 65546 falls into the 16-th block in a file. Block 16 is contained as the 10-th +// item in SortedRangeSet("1-9 15-19"). So its data can be found at offset 40970 (i.e. 4096 * 10 +// + 10) in a range represented by this SortedRangeSet. +size_t SortedRangeSet::GetOffsetInRangeSet(size_t old_offset) const { + size_t old_block_start = old_offset / kBlockSize; + size_t new_block_start = 0; + for (const auto& range : ranges_) { + // Find the index of old_block_start. + if (old_block_start >= range.second) { + new_block_start += (range.second - range.first); + } else if (old_block_start >= range.first) { + new_block_start += (old_block_start - range.first); + return (new_block_start * kBlockSize + old_offset % kBlockSize); + } else { + CHECK(false) << "block_start " << old_block_start + << " is missing between two ranges: " << this->ToString(); + return 0; + } + } + CHECK(false) << "block_start " << old_block_start + << " exceeds the limit of current RangeSet: " << this->ToString(); + return 0; +} -- cgit v1.2.3 From 6798315327690fdbe93add15159be5b925779bfe Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 4 Nov 2017 00:08:08 -0700 Subject: otautil: Remove the aborts in RangeSet::Parse(). We used to CHECK and abort on parsing errors. While it works fine for the updater use case (because recovery starts updater in a forked process and collects the process exit code), it's difficult for other clients to use RangeSet as a library (e.g. update_verifier). This CL switches the aborts to returning empty RangeSet instead. Callers need to check the parsing results explicitly. The CL also separates RangeSet::PushBack() into a function, and moves SortedRangeSet::Clear() into RangeSet. Test: recovery_unit_test Test: Sideload an OTA package with the new updater on angler. Test: Sideload an OTA package with injected range string errors. The updater aborts from the explicit checks. Change-Id: If2b7f6f41dc93af917a21c7877a83e98dc3fd016 --- otautil/include/otautil/rangeset.h | 42 ++++++++++++++----- otautil/rangeset.cpp | 85 +++++++++++++++++++++++++------------- 2 files changed, 87 insertions(+), 40 deletions(-) (limited to 'otautil') diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h index c4234d181..af8ae2dee 100644 --- a/otautil/include/otautil/rangeset.h +++ b/otautil/include/otautil/rangeset.h @@ -30,28 +30,35 @@ class RangeSet { explicit RangeSet(std::vector&& pairs); + // Parses the given string into a RangeSet. Returns the parsed RangeSet, or an empty RangeSet on + // errors. static RangeSet Parse(const std::string& range_text); + // Appends the given Range to the current RangeSet. + bool PushBack(Range range); + + // Clears all the ranges from the RangeSet. + void Clear(); + std::string ToString() const; - // Get the block number for the i-th (starting from 0) block in the RangeSet. + // Gets the block number for the i-th (starting from 0) block in the RangeSet. size_t GetBlockNumber(size_t idx) const; - // RangeSet has half-closed half-open bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" - // and "5,7" are not overlapped. + // Returns whether the current RangeSet overlaps with other. RangeSet has half-closed half-open + // bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" and "5,7" are not overlapped. bool Overlaps(const RangeSet& other) const; - // size() gives the number of Range's in this RangeSet. + // Returns the number of Range's in this RangeSet. size_t size() const { return ranges_.size(); } - // blocks() gives the number of all blocks in this RangeSet. + // Returns the total number of blocks in this RangeSet. size_t blocks() const { return blocks_; } - // We provide const iterators only. std::vector::const_iterator cbegin() const { return ranges_.cbegin(); } @@ -60,13 +67,20 @@ class RangeSet { return ranges_.cend(); } - // Need to provide begin()/end() since range-based loop expects begin()/end(). + std::vector::iterator begin() { + return ranges_.begin(); + } + + std::vector::iterator end() { + return ranges_.end(); + } + std::vector::const_iterator begin() const { - return ranges_.cbegin(); + return ranges_.begin(); } std::vector::const_iterator end() const { - return ranges_.cend(); + return ranges_.end(); } // Reverse const iterators for MoveRange(). @@ -78,6 +92,11 @@ class RangeSet { return ranges_.crend(); } + // Returns whether the RangeSet is valid (i.e. non-empty). + explicit operator bool() const { + return !ranges_.empty(); + } + const Range& operator[](size_t i) const { return ranges_[i]; } @@ -109,6 +128,9 @@ class RangeSet { // every block in the original source. class SortedRangeSet : public RangeSet { public: + // The block size when working with offset and file length. + static constexpr size_t kBlockSize = 4096; + SortedRangeSet() {} // Ranges in the the set should be mutually exclusive; and they're sorted by the start block. @@ -122,8 +144,6 @@ class SortedRangeSet : public RangeSet { // Compute the block range the file occupies, and insert that range. void Insert(size_t start, size_t len); - void Clear(); - using RangeSet::Overlaps; bool Overlaps(size_t start, size_t len) const; diff --git a/otautil/rangeset.cpp b/otautil/rangeset.cpp index a121a4efc..532cba4a8 100644 --- a/otautil/rangeset.cpp +++ b/otautil/rangeset.cpp @@ -16,8 +16,10 @@ #include "otautil/rangeset.h" +#include #include +#include #include #include #include @@ -28,47 +30,79 @@ #include RangeSet::RangeSet(std::vector&& pairs) { - CHECK_NE(pairs.size(), static_cast(0)) << "Invalid number of tokens"; + blocks_ = 0; + if (pairs.empty()) { + LOG(ERROR) << "Invalid number of tokens"; + return; + } - // Sanity check the input. - size_t result = 0; for (const auto& range : pairs) { - CHECK_LT(range.first, range.second) << "Empty or negative range: " << range.first << ", " - << range.second; - size_t sz = range.second - range.first; - CHECK_LE(result, SIZE_MAX - sz) << "RangeSet size overflow"; - result += sz; + if (!PushBack(range)) { + Clear(); + return; + } } - - ranges_ = pairs; - blocks_ = result; } RangeSet RangeSet::Parse(const std::string& range_text) { std::vector pieces = android::base::Split(range_text, ","); - CHECK_GE(pieces.size(), static_cast(3)) << "Invalid range text: " << range_text; + if (pieces.size() < 3) { + LOG(ERROR) << "Invalid range text: " << range_text; + return {}; + } size_t num; - CHECK(android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) - << "Failed to parse the number of tokens: " << range_text; - - CHECK_NE(num, static_cast(0)) << "Invalid number of tokens: " << range_text; - CHECK_EQ(num % 2, static_cast(0)) << "Number of tokens must be even: " << range_text; - CHECK_EQ(num, pieces.size() - 1) << "Mismatching number of tokens: " << range_text; + if (!android::base::ParseUint(pieces[0], &num, static_cast(INT_MAX))) { + LOG(ERROR) << "Failed to parse the number of tokens: " << range_text; + return {}; + } + if (num == 0) { + LOG(ERROR) << "Invalid number of tokens: " << range_text; + return {}; + } + if (num % 2 != 0) { + LOG(ERROR) << "Number of tokens must be even: " << range_text; + return {}; + } + if (num != pieces.size() - 1) { + LOG(ERROR) << "Mismatching number of tokens: " << range_text; + return {}; + } std::vector pairs; for (size_t i = 0; i < num; i += 2) { size_t first; - CHECK(android::base::ParseUint(pieces[i + 1], &first, static_cast(INT_MAX))); size_t second; - CHECK(android::base::ParseUint(pieces[i + 2], &second, static_cast(INT_MAX))); - + if (!android::base::ParseUint(pieces[i + 1], &first, static_cast(INT_MAX)) || + !android::base::ParseUint(pieces[i + 2], &second, static_cast(INT_MAX))) { + return {}; + } pairs.emplace_back(first, second); } - return RangeSet(std::move(pairs)); } +bool RangeSet::PushBack(Range range) { + if (range.first >= range.second) { + LOG(ERROR) << "Empty or negative range: " << range.first << ", " << range.second; + return false; + } + size_t sz = range.second - range.first; + if (blocks_ >= SIZE_MAX - sz) { + LOG(ERROR) << "RangeSet size overflow"; + return false; + } + + ranges_.push_back(std::move(range)); + blocks_ += sz; + return true; +} + +void RangeSet::Clear() { + ranges_.clear(); + blocks_ = 0; +} + std::string RangeSet::ToString() const { if (ranges_.empty()) { return ""; @@ -114,8 +148,6 @@ bool RangeSet::Overlaps(const RangeSet& other) const { return false; } -static constexpr size_t kBlockSize = 4096; - // Ranges in the the set should be mutually exclusive; and they're sorted by the start block. SortedRangeSet::SortedRangeSet(std::vector&& pairs) : RangeSet(std::move(pairs)) { std::sort(ranges_.begin(), ranges_.end()); @@ -158,11 +190,6 @@ void SortedRangeSet::Insert(size_t start, size_t len) { Insert(to_insert); } -void SortedRangeSet::Clear() { - blocks_ = 0; - ranges_.clear(); -} - bool SortedRangeSet::Overlaps(size_t start, size_t len) const { RangeSet rs({ { start / kBlockSize, (start + len - 1) / kBlockSize + 1 } }); return Overlaps(rs); -- cgit v1.2.3 From 160514bf2bac2ad8b1af6cb5a72d88439596ada1 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sat, 4 Nov 2017 00:08:08 -0700 Subject: Load-balancing update_verifier worker threads. Prior to this CL, the block verification works were assigned based on the pattern of the ranges, which could lead to unbalanced workloads. This CL adds RangeSet::Split() and moves update_verifier over. a) For the following care_map.txt on walleye: system 20,0,347,348,540,556,32770,33084,98306,98620,163842,164156,229378,229692,294914,295228,524289,524291,524292,524348,529059 vendor 8,0,120,135,32770,32831,94564,98304,98306 Measured the time costs prior to and with this CL with the following script. $ cat test_update_verifier.sh #!/bin/sh adb shell stop adb shell "cp /data/local/tmp/care_map.txt /data/ota_package/" for i in $(seq 1 50) do echo "Iteration: $i" adb shell "bootctl set-active-boot-slot 0" adb shell "echo 3 > /proc/sys/vm/drop_caches" adb shell "time /data/local/tmp/update_verifier" sleep 3 done Without this CL, the average time cost is 5.66s, while with the CL it's reduced to 3.2s. b) For the following care_map.txt, measured the performance on marlin: system 18,0,271,286,457,8350,32770,33022,98306,98558,163842,164094,196609,204800,229378,229630,294914,295166,501547 vendor 10,0,42,44,85,2408,32770,32806,32807,36902,74242 It takes 12.9s and 5.6s without and with the CL respectively. Fixes: 68553827 Test: recovery_unit_test Test: Flash new build and trigger update_verifier. Check the balanced block verification. Change-Id: I5fa4bf09a84e6b9b0975ee5f522724464181333f --- otautil/include/otautil/rangeset.h | 8 ++++++++ otautil/rangeset.cpp | 40 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) (limited to 'otautil') diff --git a/otautil/include/otautil/rangeset.h b/otautil/include/otautil/rangeset.h index af8ae2dee..e91d02ca6 100644 --- a/otautil/include/otautil/rangeset.h +++ b/otautil/include/otautil/rangeset.h @@ -49,6 +49,14 @@ class RangeSet { // bounds. For example, "3,5" contains blocks 3 and 4. So "3,5" and "5,7" are not overlapped. bool Overlaps(const RangeSet& other) const; + // Returns a vector of RangeSets that contain the same set of blocks represented by the current + // RangeSet. The RangeSets in the vector contain similar number of blocks, with a maximum delta + // of 1-block between any two of them. For example, 14 blocks would be split into 4 + 4 + 3 + 3, + // as opposed to 4 + 4 + 4 + 2. If the total number of blocks (T) is less than groups, it + // returns a vector of T 1-block RangeSets. Otherwise the number of the returned RangeSets must + // equal to groups. The current RangeSet remains intact after the split. + std::vector Split(size_t groups) const; + // Returns the number of Range's in this RangeSet. size_t size() const { return ranges_.size(); diff --git a/otautil/rangeset.cpp b/otautil/rangeset.cpp index 532cba4a8..96955b9d0 100644 --- a/otautil/rangeset.cpp +++ b/otautil/rangeset.cpp @@ -103,6 +103,46 @@ void RangeSet::Clear() { blocks_ = 0; } +std::vector RangeSet::Split(size_t groups) const { + if (ranges_.empty() || groups == 0) return {}; + + if (blocks_ < groups) { + groups = blocks_; + } + + // Evenly distribute blocks, with the first few groups possibly containing one more. + size_t mean = blocks_ / groups; + std::vector blocks_per_group(groups, mean); + std::fill_n(blocks_per_group.begin(), blocks_ % groups, mean + 1); + + std::vector result; + + // Forward iterate Ranges and fill up each group with the desired number of blocks. + auto it = ranges_.cbegin(); + Range range = *it; + for (const auto& blocks : blocks_per_group) { + RangeSet buffer; + size_t needed = blocks; + while (needed > 0) { + size_t range_blocks = range.second - range.first; + if (range_blocks > needed) { + // Split the current range and don't advance the iterator. + buffer.PushBack({ range.first, range.first + needed }); + range.first = range.first + needed; + break; + } + buffer.PushBack(range); + it++; + if (it != ranges_.cend()) { + range = *it; + } + needed -= range_blocks; + } + result.push_back(std::move(buffer)); + } + return result; +} + std::string RangeSet::ToString() const { if (ranges_.empty()) { return ""; -- cgit v1.2.3 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 --- otautil/Android.bp | 1 + otautil/cache_location.cpp | 32 ++++++++++++++ otautil/include/otautil/cache_location.h | 72 ++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+) create mode 100644 otautil/cache_location.cpp create mode 100644 otautil/include/otautil/cache_location.h (limited to 'otautil') 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_ -- cgit v1.2.3 From 01daebbe68943725e7b80e30082330c6bd042a88 Mon Sep 17 00:00:00 2001 From: Tianjie Xu Date: Thu, 8 Mar 2018 12:34:19 -0800 Subject: Set the update locations to default in CacheLocation's constructor Otherwise the applypatch executable will fail to back up the source file to /cache when patching the recovery image. Bug: 74198354 Test: run applypatch from boot to recovery (cherry picked from commit b4e3a370bf6fe2bbb6ad8e33d16ce3210595aaef) Change-Id: I37b7fd88d66ab49ef953d4b7dca22577bd1472e1 --- otautil/cache_location.cpp | 9 ++++----- otautil/include/otautil/cache_location.h | 5 +---- 2 files changed, 5 insertions(+), 9 deletions(-) (limited to 'otautil') diff --git a/otautil/cache_location.cpp b/otautil/cache_location.cpp index 8f289487f..8ddefec5e 100644 --- a/otautil/cache_location.cpp +++ b/otautil/cache_location.cpp @@ -25,8 +25,7 @@ CacheLocation& CacheLocation::location() { return cache_location; } -void CacheLocation::ResetLocations() { - cache_temp_source_ = kDefaultCacheTempSource; - last_command_file_ = kDefaultLastCommandFile; - stash_directory_base_ = kDefaultStashDirectoryBase; -} +CacheLocation::CacheLocation() + : 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 index 85e0d485c..f2f663816 100644 --- a/otautil/include/otautil/cache_location.h +++ b/otautil/include/otautil/cache_location.h @@ -27,9 +27,6 @@ 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_; @@ -53,7 +50,7 @@ class CacheLocation { } private: - CacheLocation() {} + CacheLocation(); DISALLOW_COPY_AND_ASSIGN(CacheLocation); // When there isn't enough room on the target filesystem to hold the patched version of the file, -- cgit v1.2.3