Merge "Add SystemUI to OWNERS for Sharesheet."
diff --git a/OWNERS b/OWNERS
index f5eff4b..4160122 100644
--- a/OWNERS
+++ b/OWNERS
@@ -18,6 +18,10 @@
svetoslavganov@google.com
yamasani@google.com
+# API changes are already covered by API-Review+1 (http://mdb/android-api-council)
+# via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
+per-file */api/*current.txt = *
+
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 878cef9..e21a6b2 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -181,7 +181,6 @@
"idmap2/Dump.cpp",
"idmap2/Lookup.cpp",
"idmap2/Main.cpp",
- "idmap2/Scan.cpp",
],
target: {
android: {
diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h
index 69eea8d..4099671 100644
--- a/cmds/idmap2/idmap2/Commands.h
+++ b/cmds/idmap2/idmap2/Commands.h
@@ -26,6 +26,5 @@
android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Dump(const std::vector<std::string>& args);
android::idmap2::Result<android::idmap2::Unit> Lookup(const std::vector<std::string>& args);
-android::idmap2::Result<android::idmap2::Unit> Scan(const std::vector<std::string>& args);
#endif // IDMAP2_IDMAP2_COMMANDS_H_
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index c441709..8323d0b 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -45,11 +45,8 @@
using android::ApkAssetsCookie;
using android::AssetManager2;
using android::ConfigDescription;
-using android::is_valid_resid;
-using android::kInvalidCookie;
using android::Res_value;
using android::ResStringPool;
-using android::ResTable_config;
using android::StringPiece16;
using android::base::StringPrintf;
using android::idmap2::CommandLineOptions;
@@ -59,7 +56,6 @@
using android::idmap2::Result;
using android::idmap2::Unit;
using android::idmap2::utils::ExtractOverlayManifestInfo;
-using android::util::Utf16ToUtf8;
namespace {
@@ -69,25 +65,23 @@
// first, try to parse as a hex number
char* endptr = nullptr;
- ResourceId resid;
- resid = strtol(res.c_str(), &endptr, kBaseHex);
+ const ResourceId parsed_resid = strtol(res.c_str(), &endptr, kBaseHex);
if (*endptr == '\0') {
- return resid;
+ return parsed_resid;
}
// next, try to parse as a package:type/name string
- resid = am.GetResourceId(res, "", fallback_package);
- if (is_valid_resid(resid)) {
- return resid;
+ if (auto resid = am.GetResourceId(res, "", fallback_package)) {
+ return *resid;
}
// end of the road: res could not be parsed
return Error("failed to obtain resource id for %s", res.c_str());
}
-void PrintValue(AssetManager2* const am, const Res_value& value, const ApkAssetsCookie& cookie,
+void PrintValue(AssetManager2* const am, const AssetManager2::SelectedValue& value,
std::string* const out) {
- switch (value.dataType) {
+ switch (value.type) {
case Res_value::TYPE_INT_DEC:
out->append(StringPrintf("%d", value.data));
break;
@@ -98,30 +92,21 @@
out->append(value.data != 0 ? "true" : "false");
break;
case Res_value::TYPE_STRING: {
- const ResStringPool* pool = am->GetStringPoolForCookie(cookie);
+ const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
out->append("\"");
- size_t len;
- if (pool->isUTF8()) {
- const char* str = pool->string8At(value.data, &len);
- out->append(str, len);
- } else {
- const char16_t* str16 = pool->stringAt(value.data, &len);
- out->append(Utf16ToUtf8(StringPiece16(str16, len)));
+ if (auto str = pool->string8ObjectAt(value.data)) {
+ out->append(*str);
}
- out->append("\"");
} break;
default:
- out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
+ out->append(StringPrintf("dataType=0x%02x data=0x%08x", value.type, value.data));
break;
}
}
Result<std::string> WARN_UNUSED GetValue(AssetManager2* const am, ResourceId resid) {
- Res_value value;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = am->GetResource(resid, true, 0, &value, &config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = am->GetResource(resid);
+ if (!value.has_value()) {
return Error("no resource 0x%08x in asset manager", resid);
}
@@ -129,41 +114,35 @@
// TODO(martenkongstad): use optional parameter GetResource(..., std::string*
// stacktrace = NULL) instead
- out.append(StringPrintf("cookie=%d ", cookie));
+ out.append(StringPrintf("cookie=%d ", value->cookie));
out.append("config='");
- out.append(config.toString().c_str());
+ out.append(value->config.toString().c_str());
out.append("' value=");
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- const android::ResolvedBag* bag = am->GetBag(static_cast<uint32_t>(value.data));
- if (bag == nullptr) {
- out.append(StringPrintf("dataType=0x%02x data=0x%08x", value.dataType, value.data));
+ if (value->type == Res_value::TYPE_REFERENCE) {
+ auto bag_result = am->GetBag(static_cast<uint32_t>(value->data));
+ if (!bag_result.has_value()) {
+ out.append(StringPrintf("dataType=0x%02x data=0x%08x", value->type, value->data));
return out;
}
+
out.append("[");
- Res_value bag_val;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie bag_cookie;
+ const android::ResolvedBag* bag = bag_result.value();
for (size_t i = 0; i < bag->entry_count; ++i) {
- const android::ResolvedBag::Entry& entry = bag->entries[i];
- bag_val = entry.value;
- bag_cookie = am->ResolveReference(entry.cookie, &bag_val, &selected_config, &flags, &ref);
- if (bag_cookie == kInvalidCookie) {
- out.append(
- StringPrintf("Error: dataType=0x%02x data=0x%08x", bag_val.dataType, bag_val.data));
+ AssetManager2::SelectedValue entry(bag, bag->entries[i]);
+ if (am->ResolveReference(entry).has_value()) {
+ out.append(StringPrintf("Error: dataType=0x%02x data=0x%08x", entry.type, entry.data));
continue;
}
- PrintValue(am, bag_val, bag_cookie, &out);
+ PrintValue(am, entry, &out);
if (i != bag->entry_count - 1) {
out.append(", ");
}
}
out.append("]");
} else {
- PrintValue(am, value, cookie, &out);
+ PrintValue(am, *value, &out);
}
return out;
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index fb093f0..aa6d0e7 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -53,8 +53,10 @@
int main(int argc, char** argv) {
SYSTRACE << "main";
const NameToFunctionMap commands = {
- {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup},
- {"scan", Scan},
+ {"create", Create},
+ {"create-multiple", CreateMultiple},
+ {"dump", Dump},
+ {"lookup", Lookup},
};
if (argc <= 1) {
PrintUsage(commands, std::cerr);
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
deleted file mode 100644
index 3625045..0000000
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * 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 <dirent.h>
-
-#include <fstream>
-#include <memory>
-#include <ostream>
-#include <set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "Commands.h"
-#include "android-base/properties.h"
-#include "idmap2/CommandLineOptions.h"
-#include "idmap2/CommandUtils.h"
-#include "idmap2/FileUtils.h"
-#include "idmap2/Idmap.h"
-#include "idmap2/Policies.h"
-#include "idmap2/PolicyUtils.h"
-#include "idmap2/ResourceUtils.h"
-#include "idmap2/Result.h"
-#include "idmap2/SysTrace.h"
-#include "idmap2/XmlParser.h"
-
-using android::idmap2::CommandLineOptions;
-using android::idmap2::Error;
-using android::idmap2::Idmap;
-using android::idmap2::Result;
-using android::idmap2::Unit;
-using android::idmap2::policy::kPolicyOdm;
-using android::idmap2::policy::kPolicyOem;
-using android::idmap2::policy::kPolicyProduct;
-using android::idmap2::policy::kPolicyPublic;
-using android::idmap2::policy::kPolicySystem;
-using android::idmap2::policy::kPolicyVendor;
-using android::idmap2::utils::ExtractOverlayManifestInfo;
-using android::idmap2::utils::FindFiles;
-using android::idmap2::utils::OverlayManifestInfo;
-using android::idmap2::utils::PoliciesToBitmaskResult;
-
-using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
-
-namespace {
-
-struct InputOverlay {
- bool operator<(InputOverlay const& rhs) const {
- return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
- }
-
- std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
- int priority; // NOLINT(misc-non-private-member-variables-in-classes)
- std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes)
- bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
-bool VendorIsQOrLater() {
- constexpr int kQSdkVersion = 29;
- constexpr int kBase = 10;
- std::string version_prop = android::base::GetProperty("ro.vndk.version", "29");
- int version = strtol(version_prop.data(), nullptr, kBase);
-
- // If the string cannot be parsed, it is a development sdk codename.
- return version >= kQSdkVersion || version == 0;
-}
-
-Result<std::unique_ptr<std::vector<std::string>>> FindApkFiles(const std::vector<std::string>& dirs,
- bool recursive) {
- SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
- const auto predicate = [](unsigned char type, const std::string& path) -> bool {
- static constexpr size_t kExtLen = 4; // strlen(".apk")
- return type == DT_REG && path.size() > kExtLen &&
- path.compare(path.size() - kExtLen, kExtLen, ".apk") == 0;
- };
- // pass apk paths through a set to filter out duplicates
- std::set<std::string> paths;
- for (const auto& dir : dirs) {
- const auto apk_paths = FindFiles(dir, recursive, predicate);
- if (!apk_paths) {
- return Error("failed to open directory %s", dir.c_str());
- }
- paths.insert(apk_paths->cbegin(), apk_paths->cend());
- }
- return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
-}
-
-std::vector<std::string> PoliciesForPath(const std::string& apk_path) {
- // clang-format off
- static const std::vector<std::pair<std::string, std::string>> values = {
- {"/odm/", kPolicyOdm},
- {"/oem/", kPolicyOem},
- {"/product/", kPolicyProduct},
- {"/system/", kPolicySystem},
- {"/system_ext/", kPolicySystem},
- {"/vendor/", kPolicyVendor},
- };
- // clang-format on
-
- std::vector<std::string> fulfilled_policies = {kPolicyPublic};
- for (auto const& pair : values) {
- if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
- fulfilled_policies.emplace_back(pair.second);
- break;
- }
- }
-
- return fulfilled_policies;
-}
-
-} // namespace
-
-Result<Unit> Scan(const std::vector<std::string>& args) {
- SYSTRACE << "Scan " << args;
- std::vector<std::string> input_directories;
- std::string target_package_name;
- std::string target_apk_path;
- std::string output_directory;
- std::vector<std::string> override_policies;
- bool recursive = false;
-
- const CommandLineOptions opts =
- CommandLineOptions("idmap2 scan")
- .MandatoryOption("--input-directory", "directory containing overlay apks to scan",
- &input_directories)
- .OptionalFlag("--recursive", "also scan subfolders of overlay-directory", &recursive)
- .MandatoryOption("--target-package-name", "package name of target package",
- &target_package_name)
- .MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
- .MandatoryOption("--output-directory",
- "directory in which to write artifacts (idmap files and overlays.list)",
- &output_directory)
- .OptionalOption(
- "--override-policy",
- "input: an overlayable policy this overlay fulfills "
- "(if none or supplied, the overlays will not have their policies overriden",
- &override_policies);
- const auto opts_ok = opts.Parse(args);
- if (!opts_ok) {
- return opts_ok.GetError();
- }
-
- const auto apk_paths = FindApkFiles(input_directories, recursive);
- if (!apk_paths) {
- return Error(apk_paths.GetError(), "failed to find apk files");
- }
-
- std::vector<InputOverlay> interesting_apks;
- for (const std::string& path : **apk_paths) {
- Result<OverlayManifestInfo> overlay_info =
- ExtractOverlayManifestInfo(path, /* assert_overlay */ false);
- if (!overlay_info) {
- return overlay_info.GetError();
- }
-
- if (!overlay_info->is_static) {
- continue;
- }
-
- if (overlay_info->target_package.empty() ||
- overlay_info->target_package != target_package_name) {
- continue;
- }
-
- if (overlay_info->priority < 0) {
- continue;
- }
-
- // Note that conditional property enablement/exclusion only applies if
- // the attribute is present. In its absence, all overlays are presumed enabled.
- if (!overlay_info->requiredSystemPropertyName.empty() &&
- !overlay_info->requiredSystemPropertyValue.empty()) {
- // if property set & equal to value, then include overlay - otherwise skip
- if (android::base::GetProperty(overlay_info->requiredSystemPropertyName, "") !=
- overlay_info->requiredSystemPropertyValue) {
- continue;
- }
- }
-
- std::vector<std::string> fulfilled_policies;
- if (!override_policies.empty()) {
- fulfilled_policies = override_policies;
- } else {
- fulfilled_policies = PoliciesForPath(path);
- }
-
- bool ignore_overlayable = false;
- if (std::find(fulfilled_policies.begin(), fulfilled_policies.end(), kPolicyVendor) !=
- fulfilled_policies.end() &&
- !VendorIsQOrLater()) {
- // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
- // restrictions on this overlay because the pre-Q platform has no understanding of
- // overlayable.
- ignore_overlayable = true;
- }
-
- std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
-
- // Sort the static overlays in ascending priority order
- InputOverlay input{path, idmap_path, overlay_info->priority, fulfilled_policies,
- ignore_overlayable};
- interesting_apks.insert(
- std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
- }
-
- std::stringstream stream;
- for (const auto& overlay : interesting_apks) {
- const auto policy_bitmask = PoliciesToBitmaskResult(overlay.policies);
- if (!policy_bitmask) {
- LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
- << "\": " << policy_bitmask.GetErrorMessage();
- continue;
- }
-
- if (!Verify(overlay.idmap_path, target_apk_path, overlay.apk_path, *policy_bitmask,
- !overlay.ignore_overlayable)) {
- std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
- "--overlay-apk-path", overlay.apk_path,
- "--idmap-path", overlay.idmap_path};
- if (overlay.ignore_overlayable) {
- create_args.emplace_back("--ignore-overlayable");
- }
-
- for (const std::string& policy : overlay.policies) {
- create_args.emplace_back("--policy");
- create_args.emplace_back(policy);
- }
-
- const auto create_ok = Create(create_args);
- if (!create_ok) {
- LOG(WARNING) << "failed to create idmap for overlay apk path \"" << overlay.apk_path
- << "\": " << create_ok.GetError().GetMessage();
- continue;
- }
- }
-
- stream << overlay.idmap_path << std::endl;
- }
-
- std::cout << stream.str();
-
- return Unit{};
-}
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index 3f03236..c4e0e1f 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -17,27 +17,13 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
#define IDMAP2_INCLUDE_IDMAP2_FILEUTILS_H_
-#include <sys/types.h>
-
-#include <functional>
-#include <memory>
#include <string>
-#include <vector>
namespace android::idmap2::utils {
constexpr const char* kIdmapCacheDir = "/data/resource-cache";
constexpr const mode_t kIdmapFilePermissionMask = 0133; // u=rw,g=r,o=r
-typedef std::function<bool(unsigned char type /* DT_* from dirent.h */, const std::string& path)>
- FindFilesPredicate;
-std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse,
- const FindFilesPredicate& predicate);
-
-std::unique_ptr<std::string> ReadFile(int fd);
-
-std::unique_ptr<std::string> ReadFile(const std::string& path);
-
bool UidHasWriteAccessToPath(uid_t uid, const std::string& path);
} // namespace android::idmap2::utils
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index 0a58ec4..f66916c 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -117,7 +117,8 @@
static Result<ResourceMapping> CreateResourceMappingLegacy(const AssetManager2* target_am,
const AssetManager2* overlay_am,
const LoadedPackage* target_package,
- const LoadedPackage* overlay_package);
+ const LoadedPackage* overlay_package,
+ LogInfo& log_info);
// Removes resources that do not pass policy or overlayable checks of the target package.
void FilterOverlayableResources(const AssetManager2* target_am,
diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp
index 3e8e329..3af1f70 100644
--- a/cmds/idmap2/libidmap2/FileUtils.cpp
+++ b/cmds/idmap2/libidmap2/FileUtils.cpp
@@ -16,19 +16,7 @@
#include "idmap2/FileUtils.h"
-#include <dirent.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cerrno>
-#include <climits>
-#include <cstdlib>
-#include <cstring>
-#include <fstream>
-#include <memory>
#include <string>
-#include <utility>
-#include <vector>
#include "android-base/file.h"
#include "android-base/macros.h"
@@ -37,54 +25,6 @@
namespace android::idmap2::utils {
-std::unique_ptr<std::vector<std::string>> FindFiles(const std::string& root, bool recurse,
- const FindFilesPredicate& predicate) {
- DIR* dir = opendir(root.c_str());
- if (dir == nullptr) {
- return nullptr;
- }
- std::unique_ptr<std::vector<std::string>> vector(new std::vector<std::string>());
- struct dirent* dirent;
- while ((dirent = readdir(dir)) != nullptr) {
- const std::string path = root + "/" + dirent->d_name;
- if (predicate(dirent->d_type, path)) {
- vector->push_back(path);
- }
- if (recurse && dirent->d_type == DT_DIR && strcmp(dirent->d_name, ".") != 0 &&
- strcmp(dirent->d_name, "..") != 0) {
- auto sub_vector = FindFiles(path, recurse, predicate);
- if (!sub_vector) {
- closedir(dir);
- return nullptr;
- }
- vector->insert(vector->end(), sub_vector->begin(), sub_vector->end());
- }
- }
- closedir(dir);
-
- return vector;
-}
-
-std::unique_ptr<std::string> ReadFile(const std::string& path) {
- std::unique_ptr<std::string> str(new std::string());
- std::ifstream fin(path);
- str->append({std::istreambuf_iterator<char>(fin), std::istreambuf_iterator<char>()});
- fin.close();
- return str;
-}
-
-std::unique_ptr<std::string> ReadFile(int fd) {
- static constexpr const size_t kBufSize = 1024;
-
- std::unique_ptr<std::string> str(new std::string());
- char buf[kBufSize];
- ssize_t r;
- while ((r = read(fd, buf, sizeof(buf))) > 0) {
- str->append(buf, r);
- }
- return r == 0 ? std::move(str) : nullptr;
-}
-
#ifdef __ANDROID__
bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) {
// resolve symlinks and relative paths; the directories must exist
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index a93202a..3037a79 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -100,10 +100,9 @@
stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
<< utils::DataTypeToString(target_entry.value.data_type);
- size_t unused;
if (target_entry.value.data_type == Res_value::TYPE_STRING) {
- auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset, &unused);
- stream_ << " \"" << StringPiece16(str) << "\"";
+ auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset);
+ stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
} else {
stream_ << " " << base::StringPrintf("0x%08x", target_entry.value.data_value);
}
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 31f1c16..d777cbf 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -71,9 +71,10 @@
if (!target_package.DefinesOverlayable()) {
return (sDefaultPolicies & fulfilled_policies) != 0
? Result<Unit>({})
- : Error("overlay must be preinstalled, signed with the same signature as the target,"
- " or signed with the same signature as the package referenced through"
- " <overlay-config-signature>.");
+ : Error(
+ "overlay must be preinstalled, signed with the same signature as the target,"
+ " or signed with the same signature as the package referenced through"
+ " <overlay-config-signature>.");
}
const OverlayableInfo* overlayable_info = target_package.GetOverlayableInfo(target_resource);
@@ -119,32 +120,25 @@
Result<std::unique_ptr<Asset>> OpenNonAssetFromResource(const ResourceId& resource_id,
const AssetManager2& asset_manager) {
- Res_value value{};
- ResTable_config selected_config{};
- uint32_t flags;
- auto cookie =
- asset_manager.GetResource(resource_id, /* may_be_bag */ false,
- /* density_override */ 0U, &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = asset_manager.GetResource(resource_id);
+ if (!value.has_value()) {
return Error("failed to find resource for id 0x%08x", resource_id);
}
- if (value.dataType != Res_value::TYPE_STRING) {
+ if (value->type != Res_value::TYPE_STRING) {
return Error("resource for is 0x%08x is not a file", resource_id);
}
- auto string_pool = asset_manager.GetStringPoolForCookie(cookie);
- size_t len;
- auto file_path16 = string_pool->stringAt(value.data, &len);
- if (file_path16 == nullptr) {
- return Error("failed to find string for index %d", value.data);
+ auto string_pool = asset_manager.GetStringPoolForCookie(value->cookie);
+ auto file = string_pool->string8ObjectAt(value->data);
+ if (!file.has_value()) {
+ return Error("failed to find string for index %d", value->data);
}
// Load the overlay resource mappings from the file specified using android:resourcesMap.
- auto file_path = String8(String16(file_path16));
- auto asset = asset_manager.OpenNonAsset(file_path.c_str(), Asset::AccessMode::ACCESS_BUFFER);
+ auto asset = asset_manager.OpenNonAsset(file->c_str(), Asset::AccessMode::ACCESS_BUFFER);
if (asset == nullptr) {
- return Error("file \"%s\" not found", file_path.c_str());
+ return Error("file \"%s\" not found", file->c_str());
}
return asset;
@@ -190,16 +184,16 @@
return Error(R"(<item> tag missing expected attribute "value")");
}
- ResourceId target_id =
+ auto target_id_result =
target_am->GetResourceId(*target_resource, "", target_package->GetPackageName());
- if (target_id == 0U) {
+ if (!target_id_result.has_value()) {
log_info.Warning(LogMessage() << "failed to find resource \"" << *target_resource
<< "\" in target resources");
continue;
}
// Retrieve the compile-time resource id of the target resource.
- target_id = REWRITE_PACKAGE(target_id, target_package_id);
+ uint32_t target_id = REWRITE_PACKAGE(*target_id_result, target_package_id);
if (overlay_resource->dataType == Res_value::TYPE_STRING) {
overlay_resource->data += string_pool_offset;
@@ -220,7 +214,7 @@
Result<ResourceMapping> ResourceMapping::CreateResourceMappingLegacy(
const AssetManager2* target_am, const AssetManager2* overlay_am,
- const LoadedPackage* target_package, const LoadedPackage* overlay_package) {
+ const LoadedPackage* target_package, const LoadedPackage* overlay_package, LogInfo& log_info) {
ResourceMapping resource_mapping;
const uint8_t target_package_id = target_package->GetPackageId();
const auto end = overlay_package->end();
@@ -234,13 +228,15 @@
// Find the resource with the same type and entry name within the target package.
const std::string full_name =
base::StringPrintf("%s:%s", target_package->GetPackageName().c_str(), name->c_str());
- ResourceId target_resource = target_am->GetResourceId(full_name);
- if (target_resource == 0U) {
+ auto target_resource_result = target_am->GetResourceId(full_name);
+ if (!target_resource_result.has_value()) {
+ log_info.Warning(LogMessage() << "failed to find resource \"" << full_name
+ << "\" in target resources");
continue;
}
// Retrieve the compile-time resource id of the target resource.
- target_resource = REWRITE_PACKAGE(target_resource, target_package_id);
+ ResourceId target_resource = REWRITE_PACKAGE(*target_resource_result, target_package_id);
resource_mapping.AddMapping(target_resource, overlay_resid,
false /* rewrite_overlay_reference */);
}
@@ -347,7 +343,9 @@
auto& string_pool = (*parser)->get_strings();
string_pool_data_length = string_pool.bytes();
string_pool_data.reset(new uint8_t[string_pool_data_length]);
- memcpy(string_pool_data.get(), string_pool.data(), string_pool_data_length);
+
+ // Overlays should not be incrementally installed, so calling unsafe_ptr is fine here.
+ memcpy(string_pool_data.get(), string_pool.data().unsafe_ptr(), string_pool_data_length);
// Offset string indices by the size of the overlay resource table string pool.
string_pool_offset = overlay_arsc->GetStringPool()->size();
@@ -358,7 +356,7 @@
// If no file is specified using android:resourcesMap, it is assumed that the overlay only
// defines resources intended to override target resources of the same type and name.
resource_mapping = CreateResourceMappingLegacy(&target_asset_manager, &overlay_asset_manager,
- target_pkg, overlay_pkg);
+ target_pkg, overlay_pkg, log_info);
}
if (!resource_mapping) {
diff --git a/cmds/idmap2/libidmap2/ResourceUtils.cpp b/cmds/idmap2/libidmap2/ResourceUtils.cpp
index 98d026b..e817140 100644
--- a/cmds/idmap2/libidmap2/ResourceUtils.cpp
+++ b/cmds/idmap2/libidmap2/ResourceUtils.cpp
@@ -72,21 +72,21 @@
}
Result<std::string> ResToTypeEntryName(const AssetManager2& am, uint32_t resid) {
- AssetManager2::ResourceName name;
- if (!am.GetResourceName(resid, &name)) {
+ const auto name = am.GetResourceName(resid);
+ if (!name.has_value()) {
return Error("no resource 0x%08x in asset manager", resid);
}
std::string out;
- if (name.type != nullptr) {
- out.append(name.type, name.type_len);
+ if (name->type != nullptr) {
+ out.append(name->type, name->type_len);
} else {
- out += Utf16ToUtf8(StringPiece16(name.type16, name.type_len));
+ out += Utf16ToUtf8(StringPiece16(name->type16, name->type_len));
}
out.append("/");
- if (name.entry != nullptr) {
- out.append(name.entry, name.entry_len);
+ if (name->entry != nullptr) {
+ out.append(name->entry, name->entry_len);
} else {
- out += Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len));
+ out += Utf16ToUtf8(StringPiece16(name->entry16, name->entry_len));
}
return out;
}
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 526a560..7c55b64 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -98,18 +98,19 @@
switch ((*value).dataType) {
case Res_value::TYPE_STRING: {
- size_t len;
- const String16 value16(parser_.getStrings().stringAt((*value).data, &len));
- return std::string(String8(value16).c_str());
+ if (auto str = parser_.getStrings().string8ObjectAt((*value).data)) {
+ return std::string(str->string());
+ }
+ break;
}
case Res_value::TYPE_INT_DEC:
case Res_value::TYPE_INT_HEX:
case Res_value::TYPE_INT_BOOLEAN: {
return std::to_string((*value).data);
}
- default:
- return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
}
+
+ return Error(R"(Failed to convert attribute "%s" value to a string)", name.c_str());
}
Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 8af4037..5750ca1 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -14,73 +14,16 @@
* limitations under the License.
*/
-#include <dirent.h>
-#include <fcntl.h>
-
-#include <set>
#include <string>
#include "TestHelpers.h"
-#include "android-base/macros.h"
#include "android-base/stringprintf.h"
-#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "idmap2/FileUtils.h"
#include "private/android_filesystem_config.h"
-using ::testing::NotNull;
-
namespace android::idmap2::utils {
-TEST(FileUtilsTests, FindFilesFindEverythingNonRecursive) {
- const auto& root = GetTestDataPath();
- auto v = utils::FindFiles(root, false,
- [](unsigned char type ATTRIBUTE_UNUSED,
- const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
- ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 7U);
- ASSERT_EQ(std::set<std::string>(v->begin(), v->end()), std::set<std::string>({
- root + "/.",
- root + "/..",
- root + "/overlay",
- root + "/target",
- root + "/signature-overlay",
- root + "/system-overlay",
- root + "/system-overlay-invalid",
- }));
-}
-
-TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
- const auto& root = GetTestDataPath();
- auto v = utils::FindFiles(root, true, [](unsigned char type, const std::string& path) -> bool {
- return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
- });
- ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 11U);
- ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
- std::set<std::string>(
- {root + "/target/target.apk", root + "/target/target-no-overlayable.apk",
- root + "/overlay/overlay.apk", root + "/overlay/overlay-no-name.apk",
- root + "/overlay/overlay-no-name-static.apk", root + "/overlay/overlay-shared.apk",
- root + "/overlay/overlay-static-1.apk", root + "/overlay/overlay-static-2.apk",
- root + "/signature-overlay/signature-overlay.apk",
- root + "/system-overlay/system-overlay.apk",
- root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
-}
-
-TEST(FileUtilsTests, ReadFile) {
- int pipefd[2];
- ASSERT_EQ(pipe2(pipefd, O_CLOEXEC), 0);
-
- ASSERT_EQ(write(pipefd[1], "foobar", 6), 6);
- close(pipefd[1]);
-
- auto data = ReadFile(pipefd[0]);
- ASSERT_THAT(data, NotNull());
- ASSERT_EQ(*data, "foobar");
- close(pipefd[0]);
-}
-
#ifdef __ANDROID__
TEST(FileUtilsTests, UidHasWriteAccessToPath) {
constexpr const char* tmp_path = "/data/local/tmp/test@idmap";
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index eba102da..e7e9e4c 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -159,131 +159,6 @@
unlink(GetIdmapPath().c_str());
}
-TEST_F(Idmap2BinaryTests, Scan) {
- SKIP_TEST_IF_CANT_EXEC_IDMAP2;
-
- const std::string overlay_static_no_name_apk_path =
- GetTestDataPath() + "/overlay/overlay-no-name-static.apk";
- const std::string overlay_static_1_apk_path = GetTestDataPath() + "/overlay/overlay-static-1.apk";
- const std::string overlay_static_2_apk_path = GetTestDataPath() + "/overlay/overlay-static-2.apk";
- const std::string idmap_static_no_name_path =
- Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_no_name_apk_path);
- const std::string idmap_static_1_path =
- Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_1_apk_path);
- const std::string idmap_static_2_path =
- Idmap::CanonicalIdmapPathFor(GetTempDirPath(), overlay_static_2_apk_path);
-
- // single input directory, recursive
- // clang-format off
- auto result = ExecuteBinary({"idmap2",
- "scan",
- "--input-directory", GetTestDataPath(),
- "--recursive",
- "--target-package-name", "test.target",
- "--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath(),
- "--override-policy", "public"});
- // clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- std::stringstream expected;
- expected << idmap_static_no_name_path << std::endl;
- expected << idmap_static_1_path << std::endl;
- expected << idmap_static_2_path << std::endl;
- ASSERT_EQ(result->stdout, expected.str());
-
- auto idmap_static_no_name_raw_string = utils::ReadFile(idmap_static_no_name_path);
- auto idmap_static_no_name_raw_stream = std::istringstream(*idmap_static_no_name_raw_string);
- auto idmap_static_no_name = Idmap::FromBinaryStream(idmap_static_no_name_raw_stream);
- ASSERT_TRUE(idmap_static_no_name);
- ASSERT_IDMAP(**idmap_static_no_name, GetTargetApkPath(), overlay_static_no_name_apk_path);
-
- auto idmap_static_1_raw_string = utils::ReadFile(idmap_static_1_path);
- auto idmap_static_1_raw_stream = std::istringstream(*idmap_static_1_raw_string);
- auto idmap_static_1 = Idmap::FromBinaryStream(idmap_static_1_raw_stream);
- ASSERT_TRUE(idmap_static_1);
- ASSERT_IDMAP(**idmap_static_1, GetTargetApkPath(), overlay_static_1_apk_path);
-
- auto idmap_static_2_raw_string = utils::ReadFile(idmap_static_2_path);
- auto idmap_static_2_raw_stream = std::istringstream(*idmap_static_2_raw_string);
- auto idmap_static_2 = Idmap::FromBinaryStream(idmap_static_2_raw_stream);
- ASSERT_TRUE(idmap_static_2);
- ASSERT_IDMAP(**idmap_static_2, GetTargetApkPath(), overlay_static_2_apk_path);
-
- unlink(idmap_static_no_name_path.c_str());
- unlink(idmap_static_2_path.c_str());
- unlink(idmap_static_1_path.c_str());
-
- // multiple input directories, non-recursive
- // clang-format off
- result = ExecuteBinary({"idmap2",
- "scan",
- "--input-directory", GetTestDataPath() + "/target",
- "--input-directory", GetTestDataPath() + "/overlay",
- "--target-package-name", "test.target",
- "--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath(),
- "--override-policy", "public"});
- // clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_EQ(result->stdout, expected.str());
- unlink(idmap_static_no_name_path.c_str());
- unlink(idmap_static_2_path.c_str());
- unlink(idmap_static_1_path.c_str());
-
- // the same input directory given twice, but no duplicate entries
- // clang-format off
- result = ExecuteBinary({"idmap2",
- "scan",
- "--input-directory", GetTestDataPath(),
- "--input-directory", GetTestDataPath(),
- "--recursive",
- "--target-package-name", "test.target",
- "--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath(),
- "--override-policy", "public"});
- // clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_EQ(result->stdout, expected.str());
- unlink(idmap_static_no_name_path.c_str());
- unlink(idmap_static_2_path.c_str());
- unlink(idmap_static_1_path.c_str());
-
- // no APKs in input-directory: ok, but no output
- // clang-format off
- result = ExecuteBinary({"idmap2",
- "scan",
- "--input-directory", GetTempDirPath(),
- "--target-package-name", "test.target",
- "--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath(),
- "--override-policy", "public"});
- // clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_EQ(result->stdout, "");
-
- // the signature idmap failing to generate should not cause scanning to fail
- // clang-format off
- result = ExecuteBinary({"idmap2",
- "scan",
- "--input-directory", GetTestDataPath(),
- "--recursive",
- "--target-package-name", "test.target",
- "--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath(),
- "--override-policy", "public"});
- // clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
- ASSERT_EQ(result->stdout, expected.str());
- unlink(idmap_static_no_name_path.c_str());
- unlink(idmap_static_2_path.c_str());
- unlink(idmap_static_1_path.c_str());
-}
-
TEST_F(Idmap2BinaryTests, Lookup) {
SKIP_TEST_IF_CANT_EXEC_IDMAP2;
diff --git a/cmds/idmap2/valgrind.sh b/cmds/idmap2/valgrind.sh
index b4ebab0..84daeec 100755
--- a/cmds/idmap2/valgrind.sh
+++ b/cmds/idmap2/valgrind.sh
@@ -53,7 +53,5 @@
_eval "idmap2 create" "$valgrind idmap2 create --policy public --target-apk-path $target_path --overlay-apk-path $overlay_path --idmap-path $idmap_path"
_eval "idmap2 dump" "$valgrind idmap2 dump --idmap-path $idmap_path"
_eval "idmap2 lookup" "$valgrind idmap2 lookup --idmap-path $idmap_path --config '' --resid test.target:string/str1"
-_eval "idmap2 scan" "$valgrind idmap2 scan --input-directory ${prefix}/tests/data/overlay --recursive --target-package-name test.target --target-apk-path $target_path --output-directory /tmp --override-policy public"
-_eval "idmap2 verify" "$valgrind idmap2 verify --idmap-path $idmap_path"
_eval "idmap2_tests" "$valgrind $ANDROID_HOST_OUT/nativetest64/idmap2_tests/idmap2_tests"
exit $errors
diff --git a/core/api/current.txt b/core/api/current.txt
index d7c0213..1ef98be 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29588,6 +29588,7 @@
field public static final String ID;
field public static final String MANUFACTURER;
field public static final String MODEL;
+ field @NonNull public static final String ODM_SKU;
field public static final String PRODUCT;
field @Deprecated public static final String RADIO;
field @Deprecated public static final String SERIAL;
@@ -40687,6 +40688,28 @@
field public static final int IP_VERSION_MISMATCH = 2055; // 0x807
field public static final int IRAT_HANDOVER_FAILED = 2194; // 0x892
field public static final int IS707B_MAX_ACCESS_PROBES = 2089; // 0x829
+ field public static final int IWLAN_AUTHORIZATION_REJECTED = 9003; // 0x232b
+ field public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 16388; // 0x4004
+ field public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 16389; // 0x4005
+ field public static final int IWLAN_IKEV2_AUTH_FAILURE = 16385; // 0x4001
+ field public static final int IWLAN_IKEV2_CERT_INVALID = 16387; // 0x4003
+ field public static final int IWLAN_IKEV2_CONFIG_FAILURE = 16384; // 0x4000
+ field public static final int IWLAN_IKEV2_MSG_TIMEOUT = 16386; // 0x4002
+ field public static final int IWLAN_ILLEGAL_ME = 9006; // 0x232e
+ field public static final int IWLAN_IMEI_NOT_ACCEPTED = 11005; // 0x2afd
+ field public static final int IWLAN_MAX_CONNECTION_REACHED = 8193; // 0x2001
+ field public static final int IWLAN_NETWORK_FAILURE = 10500; // 0x2904
+ field public static final int IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED = 9000; // 0x2328
+ field public static final int IWLAN_NO_APN_SUBSCRIPTION = 9002; // 0x232a
+ field public static final int IWLAN_PDN_CONNECTION_REJECTION = 8192; // 0x2000
+ field public static final int IWLAN_PLMN_NOT_ALLOWED = 11011; // 0x2b03
+ field public static final int IWLAN_RAT_TYPE_NOT_ALLOWED = 11001; // 0x2af9
+ field public static final int IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS = 8244; // 0x2034
+ field public static final int IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 8241; // 0x2031
+ field public static final int IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 8245; // 0x2035
+ field public static final int IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 8242; // 0x2032
+ field public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 11055; // 0x2b2f
+ field public static final int IWLAN_USER_UNKNOWN = 9001; // 0x2329
field public static final int LIMITED_TO_IPV4 = 2234; // 0x8ba
field public static final int LIMITED_TO_IPV6 = 2235; // 0x8bb
field public static final int LLC_SNDCP = 25; // 0x19
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index e857951..b982dd7 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -6401,6 +6401,19 @@
method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
}
+ public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+ ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
+ field public final int ipTos;
+ field public final int ipTtl;
+ field public final int tcpAck;
+ field public final int tcpSeq;
+ field public final int tcpWindow;
+ field public final int tcpWindowScale;
+ }
+
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
@@ -7001,6 +7014,7 @@
public abstract static class BugreportManager.BugreportCallback {
ctor public BugreportManager.BugreportCallback();
+ method public void onEarlyReportFinished();
method public void onError(int);
method public void onFinished();
method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
@@ -7885,6 +7899,7 @@
field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
field public static final String NAMESPACE_MEDIA_NATIVE = "media_native";
field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
+ field public static final String NAMESPACE_OTA = "ota";
field public static final String NAMESPACE_PACKAGE_MANAGER_SERVICE = "package_manager_service";
field public static final String NAMESPACE_PERMISSIONS = "permissions";
field public static final String NAMESPACE_PRIVACY = "privacy";
diff --git a/core/java/android/app/OWNERS b/core/java/android/app/OWNERS
index f10853a..06ad9c9 100644
--- a/core/java/android/app/OWNERS
+++ b/core/java/android/app/OWNERS
@@ -1,4 +1,34 @@
+
+# Remain no owner because multiple modules may touch this file.
+per-file ContextImpl.java = *
+
+# ActivityThread
+per-file ActivityThread.java = file:/services/core/java/com/android/server/am/OWNERS
+per-file ActivityThread.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# Alarm
per-file *Alarm* = file:/apex/jobscheduler/OWNERS
+
+# AppOps
per-file *AppOp* = file:/core/java/android/permission/OWNERS
+
+# Notification
per-file *Notification* = file:/packages/SystemUI/OWNERS
+
+# ResourcesManager
+per-file ResourcesManager = rtmitchell@google.com, toddke@google.com
+
+# Wallpaper
+per-file *Wallpaper* = file:/core/java/android/service/wallpaper/OWNERS
+
+# WindowManager
+per-file *Activity* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ClientTransactionHandler.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Fragment.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file *Task* = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Window* = file:/services/core/java/com/android/server/wm/OWNERS
+
+# TODO(b/174932174): determine the ownership of KeyguardManager.java
+
+# Zygote
per-file *Zygote* = file:/ZYGOTE_OWNERS
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 496ac3b..82e48bf 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -113,7 +113,6 @@
import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.net.ConnectivityDiagnosticsManager;
import android.net.ConnectivityManager;
-import android.net.ConnectivityThread;
import android.net.EthernetManager;
import android.net.IConnectivityManager;
import android.net.IEthernetManager;
@@ -768,8 +767,7 @@
public LowpanManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.LOWPAN_SERVICE);
ILowpanManager service = ILowpanManager.Stub.asInterface(b);
- return new LowpanManager(ctx.getOuterContext(), service,
- ConnectivityThread.getInstanceLooper());
+ return new LowpanManager(ctx.getOuterContext(), service);
}});
registerService(Context.ETHERNET_SERVICE, EthernetManager.class,
diff --git a/core/java/android/app/admin/OWNERS b/core/java/android/app/admin/OWNERS
index 64a1d27..8462cbe 100644
--- a/core/java/android/app/admin/OWNERS
+++ b/core/java/android/app/admin/OWNERS
@@ -1,4 +1,11 @@
# Bug component: 142675
-yamasani@google.com
+# Android Enterprise team
rubinxu@google.com
+sandness@google.com
+eranm@google.com
+alexkershaw@google.com
+pgrafov@google.com
+
+# Emeritus
+yamasani@google.com
diff --git a/core/java/android/app/time/OWNERS b/core/java/android/app/time/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/java/android/app/time/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.aidl b/core/java/android/app/timedetector/GnssTimeSuggestion.aidl
new file mode 100644
index 0000000..81475ec
--- /dev/null
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.app.timedetector;
+
+parcelable GnssTimeSuggestion;
diff --git a/core/java/android/app/timedetector/GnssTimeSuggestion.java b/core/java/android/app/timedetector/GnssTimeSuggestion.java
new file mode 100644
index 0000000..6478a2d
--- /dev/null
+++ b/core/java/android/app/timedetector/GnssTimeSuggestion.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.app.timedetector;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.TimestampedValue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A time signal from a GNSS source.
+ *
+ * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds
+ * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the
+ * elapsed realtime clock when the {@code utcTime.value} was established.
+ * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
+ * suggestions cannot be persisted across device resets.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was entered. This information exists only to aid in
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
+ * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
+ *
+ * @hide
+ */
+public final class GnssTimeSuggestion implements Parcelable {
+
+ public static final @NonNull Creator<GnssTimeSuggestion> CREATOR =
+ new Creator<GnssTimeSuggestion>() {
+ public GnssTimeSuggestion createFromParcel(Parcel in) {
+ return GnssTimeSuggestion.createFromParcel(in);
+ }
+
+ public GnssTimeSuggestion[] newArray(int size) {
+ return new GnssTimeSuggestion[size];
+ }
+ };
+
+ @NonNull private final TimestampedValue<Long> mUtcTime;
+ @Nullable private ArrayList<String> mDebugInfo;
+
+ public GnssTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
+ mUtcTime = Objects.requireNonNull(utcTime);
+ Objects.requireNonNull(utcTime.getValue());
+ }
+
+ private static GnssTimeSuggestion createFromParcel(Parcel in) {
+ TimestampedValue<Long> utcTime = in.readParcelable(null /* classLoader */);
+ GnssTimeSuggestion suggestion = new GnssTimeSuggestion(utcTime);
+ @SuppressWarnings("unchecked")
+ ArrayList<String> debugInfo = (ArrayList<String>) in.readArrayList(null /* classLoader */);
+ suggestion.mDebugInfo = debugInfo;
+ return suggestion;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeParcelable(mUtcTime, 0);
+ dest.writeList(mDebugInfo);
+ }
+
+ @NonNull
+ public TimestampedValue<Long> getUtcTime() {
+ return mUtcTime;
+ }
+
+ @NonNull
+ public List<String> getDebugInfo() {
+ return mDebugInfo == null
+ ? Collections.emptyList() : Collections.unmodifiableList(mDebugInfo);
+ }
+
+ /**
+ * Associates information with the instance that can be useful for debugging / logging. The
+ * information is present in {@link #toString()} but is not considered for
+ * {@link #equals(Object)} and {@link #hashCode()}.
+ */
+ public void addDebugInfo(String... debugInfos) {
+ if (mDebugInfo == null) {
+ mDebugInfo = new ArrayList<>();
+ }
+ mDebugInfo.addAll(Arrays.asList(debugInfos));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ GnssTimeSuggestion that = (GnssTimeSuggestion) o;
+ return Objects.equals(mUtcTime, that.mUtcTime);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mUtcTime);
+ }
+
+ @Override
+ public String toString() {
+ return "GnssTimeSuggestion{"
+ + "mUtcTime=" + mUtcTime
+ + ", mDebugInfo=" + mDebugInfo
+ + '}';
+ }
+}
diff --git a/core/java/android/app/timedetector/ITimeDetectorService.aidl b/core/java/android/app/timedetector/ITimeDetectorService.aidl
index 7bea5d7..87e7233 100644
--- a/core/java/android/app/timedetector/ITimeDetectorService.aidl
+++ b/core/java/android/app/timedetector/ITimeDetectorService.aidl
@@ -16,6 +16,7 @@
package android.app.timedetector;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -34,6 +35,7 @@
* {@hide}
*/
interface ITimeDetectorService {
+ void suggestGnssTime(in GnssTimeSuggestion timeSuggestion);
boolean suggestManualTime(in ManualTimeSuggestion timeSuggestion);
void suggestNetworkTime(in NetworkTimeSuggestion timeSuggestion);
void suggestTelephonyTime(in TelephonyTimeSuggestion timeSuggestion);
diff --git a/core/java/android/app/timedetector/OWNERS b/core/java/android/app/timedetector/OWNERS
index 8c11324..941eed8 100644
--- a/core/java/android/app/timedetector/OWNERS
+++ b/core/java/android/app/timedetector/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 847766
-
+mingaleev@google.com
narayan@google.com
nfuller@google.com
diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java
index 162e182..52016b6 100644
--- a/core/java/android/app/timedetector/TimeDetector.java
+++ b/core/java/android/app/timedetector/TimeDetector.java
@@ -71,4 +71,12 @@
*/
@RequiresPermission(android.Manifest.permission.SET_TIME)
void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion);
+
+ /**
+ * Suggests the time according to a gnss time source.
+ *
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.SET_TIME)
+ void suggestGnssTime(GnssTimeSuggestion timeSuggestion);
}
diff --git a/core/java/android/app/timedetector/TimeDetectorImpl.java b/core/java/android/app/timedetector/TimeDetectorImpl.java
index ac02c89..b0aa3c8 100644
--- a/core/java/android/app/timedetector/TimeDetectorImpl.java
+++ b/core/java/android/app/timedetector/TimeDetectorImpl.java
@@ -74,4 +74,16 @@
throw e.rethrowFromSystemServer();
}
}
+
+ @Override
+ public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
+ if (DEBUG) {
+ Log.d(TAG, "suggestGnssTime called: " + timeSuggestion);
+ }
+ try {
+ mITimeDetectorService.suggestGnssTime(timeSuggestion);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/timezone/OWNERS b/core/java/android/app/timezone/OWNERS
index 8c11324..8f80897 100644
--- a/core/java/android/app/timezone/OWNERS
+++ b/core/java/android/app/timezone/OWNERS
@@ -1,4 +1,3 @@
# Bug component: 847766
-
-narayan@google.com
-nfuller@google.com
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/java/android/app/timezonedetector/OWNERS b/core/java/android/app/timezonedetector/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/java/android/app/timezonedetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/java/android/content/OWNERS b/core/java/android/content/OWNERS
new file mode 100644
index 0000000..c1e7e41
--- /dev/null
+++ b/core/java/android/content/OWNERS
@@ -0,0 +1,3 @@
+# Remain no owner because multiple modules may touch this file.
+per-file Context.java = *
+per-file ContextWrapper.java = *
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 36986de..13433dc 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1574,7 +1574,6 @@
private static native long nativeAssetGetLength(long assetPtr);
private static native long nativeAssetGetRemainingLength(long assetPtr);
- private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
private static native @Nullable Map nativeGetOverlayableMap(long ptr,
@NonNull String packageName);
private static native @Nullable String nativeGetOverlayablesToString(long ptr,
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 920d34f..a00ff8e 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1693,35 +1693,24 @@
private static native long nativeAllocateCopy(long ptr)
throws NullPointerException;
- @FastNative
private static synchronized native void nativeWriteToParcel(Parcel dest, long ptr);
- @FastNative
private static synchronized native void nativeReadFromParcel(Parcel source, long ptr);
- @FastNative
private static synchronized native void nativeSwap(long ptr, long otherPtr)
throws NullPointerException;
- @FastNative
private static synchronized native void nativeClose(long ptr);
- @FastNative
private static synchronized native boolean nativeIsEmpty(long ptr);
- @FastNative
private static synchronized native int nativeGetEntryCount(long ptr);
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @FastNative
private static synchronized native byte[] nativeReadValues(int tag, long ptr);
- @FastNative
private static synchronized native void nativeWriteValues(int tag, byte[] src, long ptr);
private static synchronized native void nativeDump(long ptr) throws IOException; // dump to LOGD
- @FastNative
private static synchronized native ArrayList nativeGetAllVendorKeys(long ptr, Class keyClass);
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @FastNative
private static synchronized native int nativeGetTagFromKeyLocal(long ptr, String keyName)
throws IllegalArgumentException;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- @FastNative
private static synchronized native int nativeGetTypeFromTagLocal(long ptr, int tag)
throws IllegalArgumentException;
@FastNative
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index cf5d4e5..1e96872 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2108,17 +2108,6 @@
// ignored
}
- /** {@hide} */
- @Deprecated
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
- try {
- return mService.getActiveNetworkQuotaInfo();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
/**
* @hide
* @deprecated Talk to TelephonyManager directly
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4173200..fb01283 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -25,7 +25,6 @@
import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
-import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
@@ -76,7 +75,6 @@
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
- NetworkQuotaInfo getActiveNetworkQuotaInfo();
boolean isActiveNetworkMetered();
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress,
diff --git a/core/java/android/net/TcpKeepalivePacketData.java b/core/java/android/net/TcpKeepalivePacketData.java
new file mode 100644
index 0000000..ddb3a6a7
--- /dev/null
+++ b/core/java/android/net/TcpKeepalivePacketData.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+package android.net;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.InetAddress;
+import java.util.Objects;
+
+/**
+ * Represents the actual tcp keep alive packets which will be used for hardware offload.
+ * @hide
+ */
+@SystemApi
+public final class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
+ private static final String TAG = "TcpKeepalivePacketData";
+
+ /** TCP sequence number. */
+ public final int tcpSeq;
+
+ /** TCP ACK number. */
+ public final int tcpAck;
+
+ /** TCP RCV window. */
+ public final int tcpWindow;
+
+ /** TCP RCV window scale. */
+ public final int tcpWindowScale;
+
+ /** IP TOS. */
+ public final int ipTos;
+
+ /** IP TTL. */
+ public final int ipTtl;
+
+ public TcpKeepalivePacketData(@NonNull final InetAddress srcAddress, int srcPort,
+ @NonNull final InetAddress dstAddress, int dstPort, @NonNull final byte[] data,
+ int tcpSeq, int tcpAck, int tcpWindow, int tcpWindowScale, int ipTos, int ipTtl)
+ throws InvalidPacketException {
+ super(srcAddress, srcPort, dstAddress, dstPort, data);
+ this.tcpSeq = tcpSeq;
+ this.tcpAck = tcpAck;
+ this.tcpWindow = tcpWindow;
+ this.tcpWindowScale = tcpWindowScale;
+ this.ipTos = ipTos;
+ this.ipTtl = ipTtl;
+ }
+
+ @Override
+ public boolean equals(@Nullable final Object o) {
+ if (!(o instanceof TcpKeepalivePacketData)) return false;
+ final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
+ final InetAddress srcAddress = getSrcAddress();
+ final InetAddress dstAddress = getDstAddress();
+ return srcAddress.equals(other.getSrcAddress())
+ && dstAddress.equals(other.getDstAddress())
+ && getSrcPort() == other.getSrcPort()
+ && getDstPort() == other.getDstPort()
+ && this.tcpAck == other.tcpAck
+ && this.tcpSeq == other.tcpSeq
+ && this.tcpWindow == other.tcpWindow
+ && this.tcpWindowScale == other.tcpWindowScale
+ && this.ipTos == other.ipTos
+ && this.ipTtl == other.ipTtl;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(),
+ tcpAck, tcpSeq, tcpWindow, tcpWindowScale, ipTos, ipTtl);
+ }
+
+ /**
+ * Parcelable Implementation.
+ * Note that this object implements parcelable (and needs to keep doing this as it inherits
+ * from a class that does), but should usually be parceled as a stable parcelable using
+ * the toStableParcelable() and fromStableParcelable() methods.
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel. */
+ @Override
+ public void writeToParcel(@NonNull Parcel out, int flags) {
+ out.writeString(getSrcAddress().getHostAddress());
+ out.writeString(getDstAddress().getHostAddress());
+ out.writeInt(getSrcPort());
+ out.writeInt(getDstPort());
+ out.writeByteArray(getPacket());
+ out.writeInt(tcpSeq);
+ out.writeInt(tcpAck);
+ out.writeInt(tcpWindow);
+ out.writeInt(tcpWindowScale);
+ out.writeInt(ipTos);
+ out.writeInt(ipTtl);
+ }
+
+ private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
+ InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
+ InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
+ int srcPort = in.readInt();
+ int dstPort = in.readInt();
+ byte[] packet = in.createByteArray();
+ int tcpSeq = in.readInt();
+ int tcpAck = in.readInt();
+ int tcpWnd = in.readInt();
+ int tcpWndScale = in.readInt();
+ int ipTos = in.readInt();
+ int ipTtl = in.readInt();
+ return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
+ tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
+ }
+
+ /** Parcelable Creator. */
+ public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
+ new Parcelable.Creator<TcpKeepalivePacketData>() {
+ public TcpKeepalivePacketData createFromParcel(Parcel in) {
+ try {
+ return readFromParcel(in);
+ } catch (InvalidPacketException e) {
+ throw new IllegalArgumentException(
+ "Invalid TCP keepalive data: " + e.getError());
+ }
+ }
+
+ public TcpKeepalivePacketData[] newArray(int size) {
+ return new TcpKeepalivePacketData[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "saddr: " + getSrcAddress()
+ + " daddr: " + getDstAddress()
+ + " sport: " + getSrcPort()
+ + " dport: " + getDstPort()
+ + " seq: " + tcpSeq
+ + " ack: " + tcpAck
+ + " window: " + tcpWindow
+ + " windowScale: " + tcpWindowScale
+ + " tos: " + ipTos
+ + " ttl: " + ipTtl;
+ }
+}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index fe4d729..46ad7b8 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -26,7 +26,6 @@
import android.annotation.SystemService;
import android.app.ActivityManager;
import android.content.Context;
-import android.content.Intent;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
@@ -52,8 +51,6 @@
public final class BugreportManager {
private static final String TAG = "BugreportManager";
- private static final String INTENT_UI_INTENSIVE_BUGREPORT_DUMPS_FINISHED =
- "com.android.internal.intent.action.UI_INTENSIVE_BUGREPORT_DUMPS_FINISHED";
private final Context mContext;
private final IDumpstate mBinder;
@@ -126,6 +123,12 @@
* Called when taking bugreport finishes successfully.
*/
public void onFinished() {}
+
+ /**
+ * Called when it is ready for calling app to show UI, showing any extra UI before this
+ * callback can interfere with bugreport generation.
+ */
+ public void onEarlyReportFinished() {}
}
/**
@@ -288,21 +291,12 @@
}
@Override
- public void onUiIntensiveBugreportDumpsFinished(String callingPackage)
+ public void onUiIntensiveBugreportDumpsFinished()
throws RemoteException {
final long identity = Binder.clearCallingIdentity();
try {
mExecutor.execute(() -> {
- // Send intent to let calling app to show UI safely without interfering with
- // the bugreport/screenshot generation.
- // TODO(b/154298410): When S is ready for API change, add a method in
- // BugreportCallback so we can just call the callback instead of using
- // broadcast.
- Intent intent = new Intent(INTENT_UI_INTENSIVE_BUGREPORT_DUMPS_FINISHED);
- intent.setPackage(callingPackage);
- intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
- mContext.sendBroadcast(intent, android.Manifest.permission.DUMP);
+ mCallback.onEarlyReportFinished();
});
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 78ba7f0..0d8769e 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -106,12 +106,24 @@
public static final String HARDWARE = getString("ro.hardware");
/**
- * The hardware variant (SKU), if available.
+ * The SKU of the hardware (from the kernel command line). The SKU is reported by the bootloader
+ * to configure system software features.
*/
@NonNull
public static final String SKU = getString("ro.boot.hardware.sku");
/**
+ * The SKU of the device as set by the original design manufacturer (ODM). This is a
+ * runtime-initialized property set during startup to configure device services.
+ *
+ * <p>The ODM SKU may have multiple variants for the same system SKU in case a manufacturer
+ * produces variants of the same design. For example, the same build may be released with
+ * variations in physical keyboard and/or display hardware, each with a different ODM SKU.
+ */
+ @NonNull
+ public static final String ODM_SKU = getString("ro.boot.product.hardware.sku");
+
+ /**
* Whether this build was for an emulator device.
* @hide
*/
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index e1d9005..25d84ba 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -321,16 +321,6 @@
void setFirewallChainEnabled(int chain, boolean enable);
/**
- * Set all packets from users in ranges to go through VPN specified by netId.
- */
- void addVpnUidRanges(int netId, in UidRange[] ranges);
-
- /**
- * Clears the special VPN rules for users in ranges and VPN specified by netId.
- */
- void removeVpnUidRanges(int netId, in UidRange[] ranges);
-
- /**
* Start listening for mobile activity state changes.
*/
void registerNetworkActivityListener(INetworkActivityListener listener);
@@ -361,7 +351,5 @@
void removeInterfaceFromLocalNetwork(String iface);
int removeRoutesFromLocalNetwork(in List<RouteInfo> routes);
- void setAllowOnlyVpnForUids(boolean enable, in UidRange[] uidRanges);
-
boolean isNetworkRestricted(int uid);
}
diff --git a/core/java/android/os/OWNERS b/core/java/android/os/OWNERS
index 6aa1be9..563ff62 100644
--- a/core/java/android/os/OWNERS
+++ b/core/java/android/os/OWNERS
@@ -28,3 +28,6 @@
per-file *Power* = file:/services/core/java/com/android/server/power/OWNERS
per-file *Telephony* = file:/telephony/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
+
+# RecoverySystem
+per-file *Recovery* = file:/services/core/java/com/android/server/recoverysystem/OWNERS
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 4d67d46..e7e2c61 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -403,6 +403,14 @@
public static final String NAMESPACE_PERMISSIONS = "permissions";
/**
+ * Namespace for ota related features.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_OTA = "ota";
+
+ /**
* Namespace for all widget related features.
*
* @hide
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 6ef9e7e..017f405 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -16,18 +16,18 @@
package android.security.keymaster;
-import android.hardware.keymint.Algorithm;
-import android.hardware.keymint.BlockMode;
-import android.hardware.keymint.Digest;
-import android.hardware.keymint.ErrorCode;
-import android.hardware.keymint.HardwareAuthenticatorType;
-import android.hardware.keymint.KeyFormat;
-import android.hardware.keymint.KeyOrigin;
-import android.hardware.keymint.KeyPurpose;
-import android.hardware.keymint.PaddingMode;
-import android.hardware.keymint.SecurityLevel;
-import android.hardware.keymint.Tag;
-import android.hardware.keymint.TagType;
+import android.hardware.security.keymint.Algorithm;
+import android.hardware.security.keymint.BlockMode;
+import android.hardware.security.keymint.Digest;
+import android.hardware.security.keymint.ErrorCode;
+import android.hardware.security.keymint.HardwareAuthenticatorType;
+import android.hardware.security.keymint.KeyFormat;
+import android.hardware.security.keymint.KeyOrigin;
+import android.hardware.security.keymint.KeyPurpose;
+import android.hardware.security.keymint.PaddingMode;
+import android.hardware.security.keymint.SecurityLevel;
+import android.hardware.security.keymint.Tag;
+import android.hardware.security.keymint.TagType;
import java.util.HashMap;
import java.util.Map;
diff --git a/core/java/android/service/textservice/OWNERS b/core/java/android/service/textservice/OWNERS
index a637754..10b8b76 100644
--- a/core/java/android/service/textservice/OWNERS
+++ b/core/java/android/service/textservice/OWNERS
@@ -1,5 +1,3 @@
# Bug component: 34867
-ogunwale@google.com
-roosa@google.com
-yukawa@google.com
+include ../../inputmethodservice/OWNERS
\ No newline at end of file
diff --git a/core/java/android/timezone/OWNERS b/core/java/android/timezone/OWNERS
index 09447a9..8f80897 100644
--- a/core/java/android/timezone/OWNERS
+++ b/core/java/android/timezone/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/java/android/view/OWNERS b/core/java/android/view/OWNERS
index 4f82b86..72fa4c3 100644
--- a/core/java/android/view/OWNERS
+++ b/core/java/android/view/OWNERS
@@ -8,19 +8,67 @@
sumir@google.com
ogunwale@google.com
jjaggi@google.com
+roosa@google.com
# Display
-per-file Display.java = michaelwr@google.com, santoscordon@google.com
-per-file DisplayInfo.java = michaelwr@google.com, santoscordon@google.com
+per-file Display*.java = file:/services/core/java/com/android/server/display/OWNERS
+per-file Display*.aidl = file:/services/core/java/com/android/server/display/OWNERS
# Haptics
-per-file HapticFeedbackConstants.java = michaelwr@google.com, santoscordon@google.com
+per-file HapticFeedbackConstants.java = file:/services/core/java/com/android/server/input/OWNERS
+
+# Ime
+per-file Ime*.java = file:/core/java/android/view/inputmethod/OWNERS
# Input
-per-file IInputMonitorHost.aidl = michaelwr@google.com, svv@google.com
-per-file Input*.java = michaelwr@google.com, svv@google.com
-per-file Input*.aidl = michaelwr@google.com, svv@google.com
-per-file KeyEvent.java = michaelwr@google.com, svv@google.com
-per-file MotionEvent.java = michaelwr@google.com, svv@google.com
-per-file PointerIcon.java = michaelwr@google.com, svv@google.com
-per-file SimulatedDpad.java = michaelwr@google.com, svv@google.com
+per-file IInput*.aidl = file:/services/core/java/com/android/server/input/OWNERS
+per-file Input*.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file Input*.aidl = file:/services/core/java/com/android/server/input/OWNERS
+per-file KeyEvent.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file MotionEvent.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file PointerIcon.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file SimulatedDpad.java = file:/services/core/java/com/android/server/input/OWNERS
+
+# InputWindowHandle
+per-file InputWindowHandle.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file InputWindowHandle.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# Surface
+per-file Surface.java = file:/graphics/java/android/graphics/OWNERS
+per-file Surface.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceView.java = file:/graphics/java/android/graphics/OWNERS
+per-file SurfaceView.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceHolder.java = file:/graphics/java/android/graphics/OWNERS
+per-file SurfaceHolder.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# View
+per-file View.java = file:/services/accessibility/OWNERS
+per-file View.java = file:/core/java/android/service/autofill/OWNERS
+per-file View.java = file:/graphics/java/android/graphics/OWNERS
+per-file View.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file View.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ViewRootImpl.java = file:/services/accessibility/OWNERS
+per-file ViewRootImpl.java = file:/core/java/android/service/autofill/OWNERS
+per-file ViewRootImpl.java = file:/graphics/java/android/graphics/OWNERS
+per-file ViewRootImpl.java = file:/services/core/java/com/android/server/input/OWNERS
+per-file ViewRootImpl.java = file:/services/core/java/com/android/server/wm/OWNERS
+
+# WindowManager
+per-file DisplayCutout.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file DisplayCutout.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file IDisplay*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Inset*.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Inset*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file IPinnedStackListener.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file IRecents*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file IRemote*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file IWindow*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file RemoteAnimation*.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file RemoteAnimation*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceControl*.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceControl*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SurfaceSession.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file SyncRtSurfaceTransactionApplier.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file ViewRootInsetsControllerHost.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file Window*.aidl = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/java/android/view/textservice/OWNERS b/core/java/android/view/textservice/OWNERS
index a637754..582be8d 100644
--- a/core/java/android/view/textservice/OWNERS
+++ b/core/java/android/view/textservice/OWNERS
@@ -1,5 +1,3 @@
# Bug component: 34867
-ogunwale@google.com
-roosa@google.com
-yukawa@google.com
+include ../inputmethod/OWNERS
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index fbb975b..718076b 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -7,3 +7,5 @@
siyamed@google.com
per-file TextView.java, EditText.java, Editor.java = siyamed@google.com, nona@google.com, clarabayarri@google.com
+
+per-file SpellChecker.java = file:../view/inputmethod/OWNERS
diff --git a/core/java/com/android/internal/view/OWNERS b/core/java/com/android/internal/view/OWNERS
new file mode 100644
index 0000000..851d1f3
--- /dev/null
+++ b/core/java/com/android/internal/view/OWNERS
@@ -0,0 +1,20 @@
+# Bug component: 25700
+
+file:/core/java/android/view/OWNERS
+
+# Autofill
+per-file IInlineSuggestions*.aidl = file:/core/java/android/service/autofill/OWNERS
+per-file InlineSuggestions*.java = file:/core/java/android/service/autofill/OWNERS
+
+# Ime
+per-file *Input* = file:/services/core/java/com/android/server/inputmethod/OWNERS
+
+# Surface
+per-file *Surface* = file:/graphics/java/android/graphics/OWNERS
+per-file *Surface* = file:/services/core/java/com/android/server/wm/OWNERS
+
+# WindowManager
+per-file AppearanceRegion = file:/services/core/java/com/android/server/wm/OWNERS
+per-file BaseIWIndow.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file RotationPolicy.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file WindowManagerPolicyThread.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/jni/OWNERS b/core/jni/OWNERS
index bcd1278..54b0340 100644
--- a/core/jni/OWNERS
+++ b/core/jni/OWNERS
@@ -6,21 +6,31 @@
per-file android_net_* = codewiz@google.com, jchalard@google.com, lorenzo@google.com, reminv@google.com, satk@google.com
# Display
-per-file android_hardware_display_* = michaelwr@google.com, santoscordon@google.com
+per-file android_hardware_display_* = file:/services/core/java/com/android/server/display/OWNERS
# Input
-per-file android_hardware_input* = michaelwr@google.com, svv@google.com
-per-file android_view_Input* = michaelwr@google.com, svv@google.com
-per-file android_view_KeyCharacterMap.* = michaelwr@google.com, svv@google.com
-per-file android_view_*KeyEvent.* = michaelwr@google.com, svv@google.com
-per-file android_view_*MotionEvent.* = michaelwr@google.com, svv@google.com
-per-file android_view_PointerIcon.* = michaelwr@google.com, svv@google.com
+per-file android_hardware_input* = file:/services/core/java/com/android/server/input/OWNERS
+per-file android_view_Input* = file:/services/core/java/com/android/server/input/OWNERS
+per-file android_view_KeyCharacterMap.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file android_view_*KeyEvent.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file android_view_*MotionEvent.* = file:/services/core/java/com/android/server/input/OWNERS
+per-file android_view_PointerIcon.* = file:/services/core/java/com/android/server/input/OWNERS
+
+# WindowManager
+per-file android_graphics_BLASTBufferQueue.cpp = file:/services/core/java/com/android/server/wm/OWNERS
+per-file android_view_Surface* = file:/services/core/java/com/android/server/wm/OWNERS
+
+# Resources
+per-file android_content_res_* = file:/core/java/android/content/res/OWNERS
+per-file android_util_AssetManager* = file:/core/java/android/content/res/OWNERS
+per-file android_util_StringBlock* = file:/core/java/android/content/res/OWNERS
+per-file android_util_XmlBlock* = file:/core/java/android/content/res/OWNERS
+per-file com_android_internal_content_om_OverlayConfig* = file:/core/java/android/content/res/OWNERS
per-file *Zygote* = file:/ZYGOTE_OWNERS
per-file Android.bp = file:platform/build/soong:/OWNERS
per-file android_animation_* = file:/core/java/android/animation/OWNERS
per-file android_app_admin_* = file:/core/java/android/app/admin/OWNERS
-per-file android_content_res_* = file:/core/java/android/content/res/OWNERS
per-file android_graphics_* = file:/graphics/java/android/graphics/OWNERS
per-file android_hardware_Usb* = file:/services/usb/OWNERS
per-file android_hardware_display_* = file:/core/java/android/hardware/display/OWNERS
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index fbdd406..444bb66 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -24,6 +24,7 @@
#include "utils/misc.h"
#include "utils/Trace.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/ScopedUtfChars.h"
@@ -347,12 +348,17 @@
return 0;
}
+ const auto buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
+
// DynamicRefTable is only needed when looking up resource references. Opening an XML file
// directly from an ApkAssets has no notion of proper resource references.
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
+ auto xml_tree = util::make_unique<ResXMLTree>(nullptr /*dynamicRefTable*/);
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index e6881b3..b2c69a0 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -39,10 +39,10 @@
#include "androidfw/AssetManager2.h"
#include "androidfw/AttributeResolution.h"
#include "androidfw/MutexGuard.h"
-#include "androidfw/PosixUtils.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/ResourceUtils.h"
+#include "android_util_AssetManager_private.h"
#include "core_jni_helpers.h"
#include "jni.h"
#include "nativehelper/JNIPlatformHelp.h"
@@ -58,7 +58,6 @@
extern "C" int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
using ::android::base::StringPrintf;
-using ::android::util::ExecuteBinary;
namespace android {
@@ -114,101 +113,17 @@
return cookie > 0 ? static_cast<ApkAssetsCookie>(cookie - 1) : kInvalidCookie;
}
-static jobjectArray NativeCreateIdmapsForStaticOverlaysTargetingAndroid(JNIEnv* env,
- jclass /*clazz*/) {
- // --input-directory can be given multiple times, but idmap2 expects the directory to exist
- std::vector<std::string> input_dirs;
- struct stat st;
- if (stat(AssetManager::VENDOR_OVERLAY_DIR, &st) == 0) {
- input_dirs.push_back(AssetManager::VENDOR_OVERLAY_DIR);
- }
-
- if (stat(AssetManager::PRODUCT_OVERLAY_DIR, &st) == 0) {
- input_dirs.push_back(AssetManager::PRODUCT_OVERLAY_DIR);
- }
-
- if (stat(AssetManager::SYSTEM_EXT_OVERLAY_DIR, &st) == 0) {
- input_dirs.push_back(AssetManager::SYSTEM_EXT_OVERLAY_DIR);
- }
-
- if (stat(AssetManager::ODM_OVERLAY_DIR, &st) == 0) {
- input_dirs.push_back(AssetManager::ODM_OVERLAY_DIR);
- }
-
- if (stat(AssetManager::OEM_OVERLAY_DIR, &st) == 0) {
- input_dirs.push_back(AssetManager::OEM_OVERLAY_DIR);
- }
-
- if (input_dirs.empty()) {
- LOG(WARNING) << "no directories for idmap2 to scan";
- return env->NewObjectArray(0, g_stringClass, nullptr);
- }
-
- if (access("/system/bin/idmap2", X_OK) == -1) {
- PLOG(WARNING) << "unable to execute idmap2";
- return nullptr;
- }
-
- std::vector<std::string> argv{"/system/bin/idmap2",
- "scan",
- "--recursive",
- "--target-package-name", "android",
- "--target-apk-path", "/system/framework/framework-res.apk",
- "--output-directory", "/data/resource-cache"};
-
- for (const auto& dir : input_dirs) {
- argv.push_back("--input-directory");
- argv.push_back(dir);
- }
-
- const auto result = ExecuteBinary(argv);
-
- if (!result) {
- LOG(ERROR) << "failed to execute idmap2";
- return nullptr;
- }
-
- if (result->status != 0) {
- LOG(ERROR) << "idmap2: " << result->stderr;
- return nullptr;
- }
-
- std::vector<std::string> idmap_paths;
- std::istringstream input(result->stdout);
- std::string path;
- while (std::getline(input, path)) {
- idmap_paths.push_back(path);
- }
-
- jobjectArray array = env->NewObjectArray(idmap_paths.size(), g_stringClass, nullptr);
- if (array == nullptr) {
- return nullptr;
- }
- for (size_t i = 0; i < idmap_paths.size(); i++) {
- const std::string path = idmap_paths[i];
- jstring java_string = env->NewStringUTF(path.c_str());
- if (env->ExceptionCheck()) {
- return nullptr;
- }
- env->SetObjectArrayElement(array, i, java_string);
- env->DeleteLocalRef(java_string);
- }
- return array;
-}
-
-static jint CopyValue(JNIEnv* env, ApkAssetsCookie cookie, const Res_value& value, uint32_t ref,
- uint32_t type_spec_flags, ResTable_config* config, jobject out_typed_value) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.dataType);
+static jint CopyValue(JNIEnv* env, const AssetManager2::SelectedValue& value,
+ jobject out_typed_value) {
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mType, value.type);
env->SetIntField(out_typed_value, gTypedValueOffsets.mAssetCookie,
- ApkAssetsCookieToJavaCookie(cookie));
+ ApkAssetsCookieToJavaCookie(value.cookie));
env->SetIntField(out_typed_value, gTypedValueOffsets.mData, value.data);
env->SetObjectField(out_typed_value, gTypedValueOffsets.mString, nullptr);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, ref);
- env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, type_spec_flags);
- if (config != nullptr) {
- env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, config->density);
- }
- return static_cast<jint>(ApkAssetsCookieToJavaCookie(cookie));
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mResourceId, value.resid);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mChangingConfigurations, value.flags);
+ env->SetIntField(out_typed_value, gTypedValueOffsets.mDensity, value.config.density);
+ return static_cast<jint>(ApkAssetsCookieToJavaCookie(value.cookie));
}
// ----------------------------------------------------------------------------
@@ -653,15 +568,15 @@
return 0;
}
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -690,15 +605,15 @@
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ApkAssetsCookie cookie = JavaCookieToApkAssetsCookie(jcookie);
- // May be nullptr.
- std::shared_ptr<const DynamicRefTable> dynamic_ref_table =
- assetmanager->GetDynamicRefTableForCookie(cookie);
+ const incfs::map_ptr<void> buffer = asset->getIncFsBuffer(true /* aligned */);
+ const size_t length = asset->getLength();
+ if (!buffer.convert<uint8_t>().verify(length)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return 0;
+ }
- std::unique_ptr<ResXMLTree> xml_tree = util::make_unique<ResXMLTree>(
- std::move(dynamic_ref_table));
- status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), true);
- asset.reset();
-
+ auto xml_tree = util::make_unique<ResXMLTree>(assetmanager->GetDynamicRefTableForCookie(cookie));
+ status_t err = xml_tree->setTo(buffer.unsafe_ptr(), length, true);
if (err != NO_ERROR) {
jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
@@ -710,67 +625,62 @@
jshort density, jobject typed_value,
jboolean resolve_references) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
- static_cast<uint16_t>(density), &value, &selected_config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = assetmanager->GetResource(static_cast<uint32_t>(resid), false /*may_be_bag*/,
+ static_cast<uint16_t>(density));
+ if (!value.has_value()) {
+ ThrowIfIOError(env, value);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = static_cast<uint32_t>(resid);
if (resolve_references) {
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ auto result = assetmanager->ResolveReference(value.value());
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
}
- return CopyValue(env, cookie, value, ref, flags, &selected_config, typed_value);
+ return CopyValue(env, *value, typed_value);
}
static jint NativeGetResourceBagValue(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jint bag_entry_id, jobject typed_value) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t type_spec_flags = bag->type_spec_flags;
- ApkAssetsCookie cookie = kInvalidCookie;
- const Res_value* bag_value = nullptr;
- for (const ResolvedBag::Entry& entry : bag) {
- if (entry.key == static_cast<uint32_t>(bag_entry_id)) {
- cookie = entry.cookie;
- bag_value = &entry.value;
+ // The legacy would find the last entry with the target bag entry id
+ using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
+ const auto rbegin = reverse_bag_iterator(end(*bag));
+ const auto rend = reverse_bag_iterator(begin(*bag));
+ auto entry = std::find_if(rbegin, rend, [bag_entry_id](auto&& e) {
+ return e.key == static_cast<uint32_t>(bag_entry_id);
+ });
- // Keep searching (the old implementation did that).
- }
- }
-
- if (cookie == kInvalidCookie) {
+ if (entry == rend) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- Res_value value = *bag_value;
- uint32_t ref = static_cast<uint32_t>(resid);
- ResTable_config selected_config;
- cookie = assetmanager->ResolveReference(cookie, &value, &selected_config, &type_spec_flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(*bag, *entry);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- return CopyValue(env, cookie, value, ref, type_spec_flags, nullptr, typed_value);
+ return CopyValue(env, attr_value, typed_value);
}
static jintArray NativeGetStyleAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (env->ExceptionCheck()) {
return nullptr;
@@ -786,42 +696,47 @@
static jobjectArray NativeGetResourceStringArray(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jobjectArray array = env->NewObjectArray(bag->entry_count, g_stringClass, nullptr);
if (array == nullptr) {
return nullptr;
}
for (uint32_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
-
// Resolve any references to their final value.
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType == Res_value::TYPE_STRING) {
- const ApkAssets* apk_assets = assetmanager->GetApkAssets()[cookie];
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ const ApkAssets* apk_assets = assetmanager->GetApkAssets()[attr_value.cookie];
const ResStringPool* pool = apk_assets->GetLoadedArsc()->GetStringPool();
jstring java_string = nullptr;
- size_t str_len;
- const char* str_utf8 = pool->string8At(value.data, &str_len);
- if (str_utf8 != nullptr) {
- java_string = env->NewStringUTF(str_utf8);
+ auto str_utf8 = pool->string8At(attr_value.data);
+ if (UNLIKELY(ThrowIfIOError(env, str_utf8))) {
+ return nullptr;
+ }
+
+ if (str_utf8.has_value()) {
+ java_string = env->NewStringUTF(str_utf8->data());
} else {
- const char16_t* str_utf16 = pool->stringAt(value.data, &str_len);
- java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16), str_len);
+ auto str_utf16 = pool->stringAt(attr_value.data);
+ if (!str_utf16.has_value()) {
+ ThrowIfIOError(env, str_utf16);
+ return nullptr;
+ }
+ java_string = env->NewString(reinterpret_cast<const jchar*>(str_utf16->data()),
+ str_utf16->size());
}
// Check for errors creating the strings (if malformed or no memory).
@@ -842,11 +757,13 @@
static jintArray NativeGetResourceStringArrayInfo(JNIEnv* env, jclass /*clazz*/, jlong ptr,
jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count * 2);
if (array == nullptr) {
return nullptr;
@@ -858,24 +775,20 @@
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ ThrowIfIOError(env, result);
return nullptr;
}
jint string_index = -1;
- if (value.dataType == Res_value::TYPE_STRING) {
- string_index = static_cast<jint>(value.data);
+ if (attr_value.type == Res_value::TYPE_STRING) {
+ string_index = static_cast<jint>(attr_value.data);
}
- buffer[i * 2] = ApkAssetsCookieToJavaCookie(cookie);
+ buffer[i * 2] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
buffer[(i * 2) + 1] = string_index;
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
@@ -884,11 +797,13 @@
static jintArray NativeGetResourceIntArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return nullptr;
}
+ const ResolvedBag* bag = *bag_result;
jintArray array = env->NewIntArray(bag->entry_count);
if (array == nullptr) {
return nullptr;
@@ -900,40 +815,39 @@
}
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t ref;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- env->ReleasePrimitiveArrayCritical(array, buffer, JNI_ABORT);
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
+ env->ReleasePrimitiveArrayCritical(array, buffer, 0);
+ ThrowIfIOError(env, result);
return nullptr;
}
- if (value.dataType >= Res_value::TYPE_FIRST_INT && value.dataType <= Res_value::TYPE_LAST_INT) {
- buffer[i] = static_cast<jint>(value.data);
+ if (attr_value.type >= Res_value::TYPE_FIRST_INT &&
+ attr_value.type <= Res_value::TYPE_LAST_INT) {
+ buffer[i] = static_cast<jint>(attr_value.data);
}
}
env->ReleasePrimitiveArrayCritical(array, buffer, 0);
return array;
}
-static jint NativeGetResourceArraySize(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jint resid) {
- ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
- return -1;
- }
- return static_cast<jint>(bag->entry_count);
+static jint NativeGetResourceArraySize(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
+ ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+ auto bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag.has_value()) {
+ ThrowIfIOError(env, bag);
+ return -1;
+ }
+ return static_cast<jint>((*bag)->entry_count);
}
static jint NativeGetResourceArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid,
jintArray out_data) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- const ResolvedBag* bag = assetmanager->GetBag(static_cast<uint32_t>(resid));
- if (bag == nullptr) {
+ auto bag_result = assetmanager->GetBag(static_cast<uint32_t>(resid));
+ if (!bag_result.has_value()) {
+ ThrowIfIOError(env, bag_result);
return -1;
}
@@ -942,8 +856,10 @@
return -1;
}
+ const ResolvedBag* bag = *bag_result;
if (static_cast<jsize>(bag->entry_count) > out_data_length * STYLE_NUM_ENTRIES) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Input array is not large enough");
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ "Input array is not large enough");
return -1;
}
@@ -954,31 +870,26 @@
jint* cursor = buffer;
for (size_t i = 0; i < bag->entry_count; i++) {
- const ResolvedBag::Entry& entry = bag->entries[i];
- Res_value value = entry.value;
- ResTable_config selected_config;
- selected_config.density = 0;
- uint32_t flags = bag->type_spec_flags;
- uint32_t ref = 0;
- ApkAssetsCookie cookie =
- assetmanager->ResolveReference(entry.cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
+ AssetManager2::SelectedValue attr_value(bag, bag->entries[i]);
+ auto result = assetmanager->ResolveReference(attr_value);
+ if (!result.has_value()) {
env->ReleasePrimitiveArrayCritical(out_data, buffer, JNI_ABORT);
+ ThrowIfIOError(env, bag_result);
return -1;
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
+ if (attr_value.type == Res_value::TYPE_REFERENCE && attr_value.data == 0) {
+ attr_value.type = Res_value::TYPE_NULL;
+ attr_value.data = Res_value::DATA_NULL_UNDEFINED;
}
- cursor[STYLE_TYPE] = static_cast<jint>(value.dataType);
- cursor[STYLE_DATA] = static_cast<jint>(value.data);
- cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- cursor[STYLE_RESOURCE_ID] = static_cast<jint>(ref);
- cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(flags);
- cursor[STYLE_DENSITY] = static_cast<jint>(selected_config.density);
+ cursor[STYLE_TYPE] = static_cast<jint>(attr_value.type);
+ cursor[STYLE_DATA] = static_cast<jint>(attr_value.data);
+ cursor[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(attr_value.cookie);
+ cursor[STYLE_RESOURCE_ID] = static_cast<jint>(attr_value.resid);
+ cursor[STYLE_CHANGING_CONFIGURATIONS] = static_cast<jint>(attr_value.flags);
+ cursor[STYLE_DENSITY] = static_cast<jint>(attr_value.config.density);
cursor += STYLE_NUM_ENTRIES;
}
env->ReleasePrimitiveArrayCritical(out_data, buffer, 0);
@@ -1006,60 +917,71 @@
CHECK(package_utf8.c_str() != nullptr);
package = package_utf8.c_str();
}
+
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- return static_cast<jint>(assetmanager->GetResourceId(name_utf8.c_str(), type, package));
+ auto resid = assetmanager->GetResourceId(name_utf8.c_str(), type, package);
+ if (!resid.has_value()) {
+ ThrowIfIOError(env, resid);
+ return 0;
+ }
+
+ return static_cast<jint>(*resid);
}
static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- std::string result = ToFormattedResourceString(&name);
+ const std::string result = ToFormattedResourceString(name.value());
return env->NewStringUTF(result.c_str());
}
static jstring NativeGetResourcePackageName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.package != nullptr) {
- return env->NewStringUTF(name.package);
+ if (name->package != nullptr) {
+ return env->NewStringUTF(name->package);
}
return nullptr;
}
static jstring NativeGetResourceTypeName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.type != nullptr) {
- return env->NewStringUTF(name.type);
- } else if (name.type16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.type16), name.type_len);
+ if (name->type != nullptr) {
+ return env->NewStringUTF(name->type);
+ } else if (name->type16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->type16), name->type_len);
}
return nullptr;
}
static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong ptr, jint resid) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- AssetManager2::ResourceName name;
- if (!assetmanager->GetResourceName(static_cast<uint32_t>(resid), &name)) {
+ auto name = assetmanager->GetResourceName(static_cast<uint32_t>(resid));
+ if (!name.has_value()) {
+ ThrowIfIOError(env, name);
return nullptr;
}
- if (name.entry != nullptr) {
- return env->NewStringUTF(name.entry);
- } else if (name.entry16 != nullptr) {
- return env->NewString(reinterpret_cast<const jchar*>(name.entry16), name.entry_len);
+ if (name->entry != nullptr) {
+ return env->NewStringUTF(name->entry);
+ } else if (name->entry16 != nullptr) {
+ return env->NewString(reinterpret_cast<const jchar*>(name->entry16), name->entry_len);
}
return nullptr;
}
@@ -1123,17 +1045,21 @@
static jobjectArray NativeGetSizeConfigurations(JNIEnv* env, jclass /*clazz*/, jlong ptr) {
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
- std::set<ResTable_config> configurations =
- assetmanager->GetResourceConfigurations(true /*exclude_system*/, false /*exclude_mipmap*/);
+ auto configurations = assetmanager->GetResourceConfigurations(true /*exclude_system*/,
+ false /*exclude_mipmap*/);
+ if (!configurations.has_value()) {
+ ThrowIfIOError(env, configurations);
+ return nullptr;
+ }
jobjectArray array =
- env->NewObjectArray(configurations.size(), gConfigurationOffsets.classObject, nullptr);
+ env->NewObjectArray(configurations->size(), gConfigurationOffsets.classObject, nullptr);
if (array == nullptr) {
return nullptr;
}
size_t idx = 0;
- for (const ResTable_config& configuration : configurations) {
+ for (const ResTable_config& configuration : *configurations) {
jobject java_configuration = ConstructConfigurationObject(env, configuration);
if (java_configuration == nullptr) {
return nullptr;
@@ -1156,13 +1082,10 @@
(void) assetmanager;
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
- }
+ auto value = theme->GetAttribute(def_style_attr);
+ if (value.has_value() && value->type == Res_value::TYPE_REFERENCE) {
+ def_style_resid = value->data;
}
}
@@ -1203,10 +1126,11 @@
return;
}
- ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
- static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(attrs), attrs_len,
- out_values, out_indices);
+ auto result = ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid),
+ reinterpret_cast<uint32_t*>(attrs), attrs_len, out_values, out_indices);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
+ ThrowIfIOError(env, result);
}
static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
@@ -1267,11 +1191,12 @@
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
-
- bool result = ResolveAttrs(
- theme, static_cast<uint32_t>(def_style_attr), static_cast<uint32_t>(def_style_resid),
- reinterpret_cast<uint32_t*>(values), values_len, reinterpret_cast<uint32_t*>(attrs),
- attrs_len, reinterpret_cast<uint32_t*>(out_values), reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ ResolveAttrs(theme, static_cast<uint32_t>(def_style_attr),
+ static_cast<uint32_t>(def_style_resid), reinterpret_cast<uint32_t*>(values),
+ values_len, reinterpret_cast<uint32_t*>(attrs), attrs_len,
+ reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
@@ -1280,8 +1205,13 @@
if (values != nullptr) {
env->ReleasePrimitiveArrayCritical(java_values, values, JNI_ABORT);
}
+
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jboolean NativeRetrieveAttributes(JNIEnv* env, jclass /*clazz*/, jlong ptr,
@@ -1322,18 +1252,22 @@
ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr);
-
- bool result = RetrieveAttributes(assetmanager.get(), xml_parser,
- reinterpret_cast<uint32_t*>(attrs), attrs_len,
- reinterpret_cast<uint32_t*>(out_values),
- reinterpret_cast<uint32_t*>(out_indices));
+ auto result =
+ RetrieveAttributes(assetmanager.get(), xml_parser, reinterpret_cast<uint32_t*>(attrs),
+ attrs_len, reinterpret_cast<uint32_t*>(out_values),
+ reinterpret_cast<uint32_t*>(out_indices));
if (out_indices != nullptr) {
env->ReleasePrimitiveArrayCritical(out_java_indices, out_indices, 0);
}
+
env->ReleasePrimitiveArrayCritical(out_java_values, out_values, 0);
env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT);
- return result ? JNI_TRUE : JNI_FALSE;
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return JNI_FALSE;
+ }
+ return JNI_TRUE;
}
static jlong NativeThemeCreate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
@@ -1352,7 +1286,9 @@
Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+
+ auto result = theme->ApplyStyle(static_cast<uint32_t>(resid), force);
+ ThrowIfIOError(env, result);
// TODO(adamlesinski): Consider surfacing exception when result is failure.
// CTS currently expects no exceptions from this method.
@@ -1365,19 +1301,22 @@
Theme* dst_theme = reinterpret_cast<Theme*>(dst_theme_ptr);
Theme* src_theme = reinterpret_cast<Theme*>(src_theme_ptr);
+ ScopedLock<AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
+ CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
+ (void) src_assetmanager;
+
if (dst_asset_manager_ptr != src_asset_manager_ptr) {
ScopedLock<AssetManager2> dst_assetmanager(AssetManagerFromLong(dst_asset_manager_ptr));
CHECK(dst_theme->GetAssetManager() == &(*dst_assetmanager));
(void) dst_assetmanager;
- ScopedLock <AssetManager2> src_assetmanager(AssetManagerFromLong(src_asset_manager_ptr));
- CHECK(src_theme->GetAssetManager() == &(*src_assetmanager));
- (void) src_assetmanager;
-
- dst_theme->SetTo(*src_theme);
- } else {
- dst_theme->SetTo(*src_theme);
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
+ return;
}
+
+ auto result = dst_theme->SetTo(*src_theme);
+ ThrowIfIOError(env, result);
}
static void NativeThemeClear(JNIEnv* /*env*/, jclass /*clazz*/, jlong theme_ptr) {
@@ -1392,23 +1331,21 @@
CHECK(theme->GetAssetManager() == &(*assetmanager));
(void) assetmanager;
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie = theme->GetAttribute(static_cast<uint32_t>(resid), &value, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = theme->GetAttribute(static_cast<uint32_t>(resid));
+ if (!value.has_value()) {
return ApkAssetsCookieToJavaCookie(kInvalidCookie);
}
- uint32_t ref = 0u;
- if (resolve_references) {
- ResTable_config selected_config;
- cookie =
- theme->GetAssetManager()->ResolveReference(cookie, &value, &selected_config, &flags, &ref);
- if (cookie == kInvalidCookie) {
- return ApkAssetsCookieToJavaCookie(kInvalidCookie);
- }
+ if (!resolve_references) {
+ return CopyValue(env, *value, typed_value);
}
- return CopyValue(env, cookie, value, ref, flags, nullptr, typed_value);
+
+ auto result = theme->GetAssetManager()->ResolveReference(*value);
+ if (!result.has_value()) {
+ ThrowIfIOError(env, result);
+ return ApkAssetsCookieToJavaCookie(kInvalidCookie);
+ }
+ return CopyValue(env, *value, typed_value);
}
static void NativeThemeDump(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
@@ -1563,8 +1500,6 @@
{"nativeAssetGetRemainingLength", "(J)J", (void*)NativeAssetGetRemainingLength},
// System/idmap related methods.
- {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
- (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
{"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
(void*)NativeGetOverlayableMap},
{"nativeGetOverlayablesToString", "(JLjava/lang/String;)Ljava/lang/String;",
diff --git a/core/jni/android_util_AssetManager_private.h b/core/jni/android_util_AssetManager_private.h
new file mode 100644
index 0000000..153509b9
--- /dev/null
+++ b/core/jni/android_util_AssetManager_private.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 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 ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
+#define ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
+
+#include <optional>
+
+#include <androidfw/Errors.h>
+#include <android-base/expected.h>
+
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "nativehelper/JNIHelp.h"
+
+namespace android {
+
+constexpr const char* kResourcesNotFound = "android/content/res/Resources$NotFoundException";
+constexpr const static char* kIOErrorMessage = "failed to read resources.arsc data";
+
+template <typename T, typename E>
+static bool ThrowIfIOError(JNIEnv* env, const base::expected<T, E>& result) {
+ if constexpr (std::is_same<NullOrIOError, E>::value) {
+ if (IsIOError(result)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ } else {
+ if (!result.has_value()) {
+ static_assert(std::is_same<IOError, E>::value, "Unknown result error type");
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return true;
+ }
+ return false;
+ }
+}
+
+} // namespace android
+
+#endif //ANDROID_UTIL_ASSETMANAGER_PRIVATE_H
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 760f9e3..45f6b72 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "StringBlock"
+#include "android_util_AssetManager_private.h"
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <utils/misc.h>
@@ -31,10 +32,8 @@
// ----------------------------------------------------------------------------
-static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
- jbyteArray bArray,
- jint off, jint len)
-{
+static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz, jbyteArray bArray,
+ jint off, jint len) {
if (bArray == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
@@ -59,9 +58,7 @@
return reinterpret_cast<jlong>(osb);
}
-static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
@@ -71,76 +68,84 @@
return osb->size();
}
-static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return 0;
}
- size_t len;
- const char* str8 = osb->string8At(idx, &len);
- if (str8 != NULL) {
- return env->NewStringUTF(str8);
+ auto str8 = osb->string8At(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str8))) {
+ return 0;
+ } else if (str8.has_value()) {
+ return env->NewStringUTF(str8->data());
}
- const char16_t* str = osb->stringAt(idx, &len);
- if (str == NULL) {
+ auto str = osb->stringAt(idx);
+ if (UNLIKELY(ThrowIfIOError(env, str))) {
+ return 0;
+ } else if (UNLIKELY(!str.has_value())) {
jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
return 0;
}
- return env->NewString((const jchar*)str, len);
+ return env->NewString((const jchar*)str->data(), str->size());
}
-static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
- jlong token, jint idx)
-{
+static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz, jlong token,
+ jint idx) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
return NULL;
}
- const ResStringPool_span* spans = osb->styleAt(idx);
- if (spans == NULL) {
+ auto spans = osb->styleAt(idx);
+ if (!spans.has_value()) {
+ ThrowIfIOError(env, spans);
return NULL;
}
- const ResStringPool_span* pos = spans;
- int num = 0;
- while (pos->name.index != ResStringPool_span::END) {
- num++;
- pos++;
- }
+ jintArray array;
+ {
+ int num = 0;
+ auto pos = *spans;
+ while (true) {
+ if (UNLIKELY(!pos)) {
+ jniThrowException(env, kResourcesNotFound, kIOErrorMessage);
+ return NULL;
+ }
+ if (pos->name.index == ResStringPool_span::END) {
+ break;
+ }
+ num++;
+ pos++;
+ }
- if (num == 0) {
- return NULL;
- }
+ if (num == 0) {
+ return NULL;
+ }
- jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
- if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
- return NULL;
+ array = env->NewIntArray((num * sizeof(ResStringPool_span)) / sizeof(jint));
+ if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
+ return NULL;
+ }
}
-
- num = 0;
- static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
- while (spans->name.index != ResStringPool_span::END) {
- env->SetIntArrayRegion(array,
- num*numInts, numInts,
- (jint*)spans);
- spans++;
- num++;
+ {
+ int num = 0;
+ static const int numInts = sizeof(ResStringPool_span) / sizeof(jint);
+ while ((*spans)->name.index != ResStringPool_span::END) {
+ env->SetIntArrayRegion(array, num * numInts, numInts, (jint*)spans->unsafe_ptr());
+ (*spans)++;
+ num++;
+ }
}
-
return array;
}
-static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
- jlong token)
-{
+static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz, jlong token) {
ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
if (osb == NULL) {
jniThrowNullPointerException(env, NULL);
diff --git a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 9246a23..f9e3bc6 100644
--- a/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -118,6 +118,7 @@
// Wifi bugreports should not receive any progress.
assertThat(callback.hasReceivedProgress()).isFalse();
assertThat(mBugreportFile.length()).isGreaterThan(0L);
+ assertThat(callback.hasEarlyReportFinished()).isTrue();
assertFdsAreClosed(mBugreportFd);
}
@@ -135,6 +136,7 @@
// Interactive bugreports show progress updates.
assertThat(callback.hasReceivedProgress()).isTrue();
assertThat(mBugreportFile.length()).isGreaterThan(0L);
+ assertThat(callback.hasEarlyReportFinished()).isTrue();
assertFdsAreClosed(mBugreportFd);
}
@@ -246,6 +248,7 @@
private int mErrorCode = -1;
private boolean mSuccess = false;
private boolean mReceivedProgress = false;
+ private boolean mEarlyReportFinished = false;
private final Object mLock = new Object();
@Override
@@ -271,6 +274,13 @@
}
}
+ @Override
+ public void onEarlyReportFinished() {
+ synchronized (mLock) {
+ mEarlyReportFinished = true;
+ }
+ }
+
/* Indicates completion; and ended up with a success or error. */
public boolean isDone() {
synchronized (mLock) {
@@ -295,6 +305,12 @@
return mReceivedProgress;
}
}
+
+ public boolean hasEarlyReportFinished() {
+ synchronized (mLock) {
+ return mEarlyReportFinished;
+ }
+ }
}
public static BugreportManager getBugreportManager() {
diff --git a/core/tests/coretests/src/android/app/OWNERS b/core/tests/coretests/src/android/app/OWNERS
new file mode 100644
index 0000000..bd7da0c
--- /dev/null
+++ b/core/tests/coretests/src/android/app/OWNERS
@@ -0,0 +1 @@
+per-file Window*.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/app/activity/OWNERS b/core/tests/coretests/src/android/app/activity/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/core/tests/coretests/src/android/app/activity/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/app/servertransaction/OWNERS b/core/tests/coretests/src/android/app/servertransaction/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/core/tests/coretests/src/android/app/servertransaction/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/coretests/src/android/app/time/OWNERS b/core/tests/coretests/src/android/app/time/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/tests/coretests/src/android/app/time/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
new file mode 100644
index 0000000..e248010
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/GnssTimeSuggestionTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2020 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.
+ */
+
+package android.app.timedetector;
+
+import static android.app.timezonedetector.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.app.timezonedetector.ParcelableTestSupport.roundTripParcelable;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.os.TimestampedValue;
+
+import org.junit.Test;
+
+public class GnssTimeSuggestionTest {
+
+ private static final TimestampedValue<Long> ARBITRARY_TIME =
+ new TimestampedValue<>(1111L, 2222L);
+
+ @Test
+ public void testEquals() {
+ GnssTimeSuggestion one = new GnssTimeSuggestion(ARBITRARY_TIME);
+ assertEquals(one, one);
+
+ GnssTimeSuggestion two = new GnssTimeSuggestion(ARBITRARY_TIME);
+ assertEquals(one, two);
+ assertEquals(two, one);
+
+ TimestampedValue<Long> differentTime = new TimestampedValue<>(
+ ARBITRARY_TIME.getReferenceTimeMillis() + 1,
+ ARBITRARY_TIME.getValue());
+ GnssTimeSuggestion three = new GnssTimeSuggestion(differentTime);
+ assertNotEquals(one, three);
+ assertNotEquals(three, one);
+
+ // DebugInfo must not be considered in equals().
+ one.addDebugInfo("Debug info 1");
+ two.addDebugInfo("Debug info 2");
+ assertEquals(one, two);
+ }
+
+ @Test
+ public void testParcelable() {
+ GnssTimeSuggestion suggestion = new GnssTimeSuggestion(ARBITRARY_TIME);
+ assertRoundTripParcelable(suggestion);
+
+ // DebugInfo should also be stored (but is not checked by equals()
+ suggestion.addDebugInfo("This is debug info");
+ GnssTimeSuggestion rtSuggestion = roundTripParcelable(suggestion);
+ assertEquals(suggestion.getDebugInfo(), rtSuggestion.getDebugInfo());
+ }
+}
diff --git a/core/tests/coretests/src/android/app/timedetector/OWNERS b/core/tests/coretests/src/android/app/timedetector/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timedetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timezone/OWNERS b/core/tests/coretests/src/android/app/timezone/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezone/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/app/timezonedetector/OWNERS b/core/tests/coretests/src/android/app/timezonedetector/OWNERS
new file mode 100644
index 0000000..8f80897
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezonedetector/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/core/tests/coretests/src/android/content/OWNERS b/core/tests/coretests/src/android/content/OWNERS
new file mode 100644
index 0000000..911efb2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/OWNERS
@@ -0,0 +1 @@
+per-file ContextTest.java = file:/services/core/java/com/android/server/wm/OWNERS
diff --git a/core/tests/mockingcoretests/src/android/app/activity/OWNERS b/core/tests/mockingcoretests/src/android/app/activity/OWNERS
new file mode 100644
index 0000000..0862c05
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/app/activity/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/wm/OWNERS
diff --git a/graphics/java/android/graphics/OWNERS b/graphics/java/android/graphics/OWNERS
index 6196889..a8a3631 100644
--- a/graphics/java/android/graphics/OWNERS
+++ b/graphics/java/android/graphics/OWNERS
@@ -4,3 +4,8 @@
jreck@google.com
njawad@google.com
sumir@google.com
+
+per-file BLASTBufferQueue.java = file:/services/core/java/com/android/server/wm/OWNERS
+per-file FontFamily.java = file:fonts/OWNERS
+per-file FontListParser.java = file:fonts/OWNERS
+per-file Typeface.java = file:fonts/OWNERS
diff --git a/keystore/java/android/security/KeyStoreOperation.java b/keystore/java/android/security/KeyStoreOperation.java
index 49a4887..7ea9e14 100644
--- a/keystore/java/android/security/KeyStoreOperation.java
+++ b/keystore/java/android/security/KeyStoreOperation.java
@@ -17,7 +17,7 @@
package android.security;
import android.annotation.NonNull;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/KeyStoreSecurityLevel.java b/keystore/java/android/security/KeyStoreSecurityLevel.java
index 7c3de8b..3ef4aa5 100644
--- a/keystore/java/android/security/KeyStoreSecurityLevel.java
+++ b/keystore/java/android/security/KeyStoreSecurityLevel.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.app.compat.CompatChanges;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.security.keystore.BackendBusyException;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
index 69c7a25..0775a1a 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStore3DESCipherSpi.java
@@ -17,7 +17,7 @@
package android.security.keystore2;
import android.annotation.NonNull;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyProperties;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 2b5f6c3..bc56f01 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
index 18d2692..a3b04ab 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreCipherSpiBase.java
@@ -19,7 +19,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
index 2250c89..d1ef1df 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECDSASignatureSpi.java
@@ -17,7 +17,7 @@
package android.security.keystore2;
import android.annotation.NonNull;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index eea45c2..8475ad9 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -16,7 +16,7 @@
package android.security.keystore2;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 479fd8a..233f352 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -16,8 +16,8 @@
package android.security.keystore2;
-import android.hardware.keymint.KeyParameter;
-import android.hardware.keymint.SecurityLevel;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.SecurityLevel;
import android.security.KeyStore2;
import android.security.KeyStoreSecurityLevel;
import android.security.keymaster.KeymasterArguments;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 61725e3..df0e146 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,8 +18,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.keymint.KeyParameter;
-import android.hardware.keymint.SecurityLevel;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.SecurityLevel;
import android.os.Build;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore2;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 2686ddc..951f918 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeymasterUtils;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
index 444dad4..ab75591 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSASignatureSpi.java
@@ -17,7 +17,7 @@
package android.security.keystore2;
import android.annotation.NonNull;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
index a168f8f..9b4f01e 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSignatureSpiBase.java
@@ -18,7 +18,7 @@
import android.annotation.CallSuper;
import android.annotation.NonNull;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.KeyStoreException;
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 9790a4a..aca5314 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -18,9 +18,9 @@
import android.annotation.NonNull;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.keymint.HardwareAuthenticatorType;
-import android.hardware.keymint.KeyParameter;
-import android.hardware.keymint.SecurityLevel;
+import android.hardware.security.keymint.HardwareAuthenticatorType;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.SecurityLevel;
import android.security.GateKeeper;
import android.security.KeyStore2;
import android.security.KeyStoreParameter;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
index a2d4528..4d4b0d8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
@@ -18,7 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.hardware.keymint.KeyParameter;
+import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyProperties;
diff --git a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
index 8fa532b..18c786a 100644
--- a/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
+++ b/keystore/java/android/security/keystore2/KeyStore2ParameterUtils.java
@@ -18,8 +18,8 @@
import android.annotation.NonNull;
import android.hardware.biometrics.BiometricManager;
-import android.hardware.keymint.KeyParameter;
-import android.hardware.keymint.SecurityLevel;
+import android.hardware.security.keymint.KeyParameter;
+import android.hardware.security.keymint.SecurityLevel;
import android.security.GateKeeper;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index aa34edf..6a7df94 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -61,6 +61,9 @@
],
export_include_dirs: ["include"],
export_shared_lib_headers: ["libz"],
+ static_libs: ["libincfs-utils"],
+ whole_static_libs: ["libincfs-utils"],
+ export_static_lib_headers: ["libincfs-utils"],
target: {
android: {
srcs: [
@@ -69,13 +72,14 @@
"CursorWindow.cpp",
],
shared_libs: [
- "libziparchive",
"libbase",
"libbinder",
"liblog",
"libcutils",
+ "libincfs",
"libutils",
"libz",
+ "libziparchive",
],
static: {
enabled: false,
@@ -86,11 +90,11 @@
enabled: false,
},
static_libs: [
- "libziparchive",
"libbase",
- "liblog",
"libcutils",
+ "liblog",
"libutils",
+ "libziparchive",
],
shared_libs: [
"libz",
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
index e15b42d..cb56a51 100755
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -25,13 +25,11 @@
#include "android-base/unique_fd.h"
#include "android-base/utf8.h"
#include "utils/Compat.h"
-#include "utils/FileMap.h"
#include "ziparchive/zip_archive.h"
#include "androidfw/Asset.h"
#include "androidfw/Idmap.h"
#include "androidfw/misc.h"
-#include "androidfw/ResourceTypes.h"
#include "androidfw/Util.h"
namespace android {
@@ -161,50 +159,46 @@
}
const int fd = ::GetFileDescriptor(zip_handle_.get());
- const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
+ const off64_t fd_offset = ::GetFileDescriptorOffset(zip_handle_.get());
+ incfs::IncFsFileMap asset_map;
if (entry.method == kCompressDeflated) {
- std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.compressed_length,
- true /*readOnly*/)) {
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.compressed_length, GetPath())) {
LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
return {};
}
std::unique_ptr<Asset> asset =
- Asset::createFromCompressedMap(std::move(map), entry.uncompressed_length, mode);
+ Asset::createFromCompressedMap(std::move(asset_map), entry.uncompressed_length, mode);
if (asset == nullptr) {
LOG(ERROR) << "Failed to decompress '" << path << "' in APK '" << friendly_name_ << "'";
return {};
}
return asset;
- } else {
- std::unique_ptr<FileMap> map = util::make_unique<FileMap>();
- if (!map->create(GetPath(), fd, entry.offset + fd_offset, entry.uncompressed_length,
- true /*readOnly*/)) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
-
- unique_fd ufd;
- if (!GetPath()) {
- // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
- // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
- // to create new file descriptors.
- ufd = unique_fd(dup(fd));
- if (!ufd.ok()) {
- LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- }
-
- std::unique_ptr<Asset> asset = Asset::createFromUncompressedMap(std::move(map),
- std::move(ufd), mode);
- if (asset == nullptr) {
- LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
- return {};
- }
- return asset;
}
+
+ if (!asset_map.Create(fd, entry.offset + fd_offset, entry.uncompressed_length, GetPath())) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
+ return {};
+ }
+
+ unique_fd ufd;
+ if (!GetPath()) {
+ // If the `path` is not set, create a new `fd` for the new Asset to own in order to create
+ // new file descriptors using Asset::openFileDescriptor. If the path is set, it will be used
+ // to create new file descriptors.
+ ufd = unique_fd(dup(fd));
+ if (!ufd.ok()) {
+ LOG(ERROR) << "Unable to dup fd '" << path << "' in APK '" << friendly_name_ << "'";
+ return {};
+ }
+ }
+
+ auto asset = Asset::createFromUncompressedMap(std::move(asset_map), mode, std::move(ufd));
+ if (asset == nullptr) {
+ LOG(ERROR) << "Failed to mmap file '" << path << "' in APK '" << friendly_name_ << "'";
+ return {};
+ }
+ return asset;
}
private:
@@ -446,8 +440,8 @@
}
}
- std::unique_ptr<FileMap> file_map = util::make_unique<FileMap>();
- if (!file_map->create(path, fd, offset, static_cast<size_t>(length), true /*readOnly*/)) {
+ incfs::IncFsFileMap file_map;
+ if (!file_map.Create(fd, offset, static_cast<size_t>(length), path)) {
LOG(ERROR) << "Failed to mmap file '" << ((path) ? path : "anon") << "': "
<< SystemErrorCodeToString(errno);
return {};
@@ -456,8 +450,8 @@
// If `path` is set, do not pass ownership of the `fd` to the new Asset since
// Asset::openFileDescriptor can use `path` to create new file descriptors.
return Asset::createFromUncompressedMap(std::move(file_map),
- (path) ? base::unique_fd(-1) : std::move(fd),
- Asset::AccessMode::ACCESS_RANDOM);
+ Asset::AccessMode::ACCESS_RANDOM,
+ (path) ? base::unique_fd(-1) : std::move(fd));
}
std::unique_ptr<const ApkAssets> ApkAssets::LoadImpl(
@@ -493,15 +487,14 @@
loaded_apk->idmap_asset_ = std::move(idmap_asset);
loaded_apk->loaded_idmap_ = std::move(idmap);
- const StringPiece data(
- reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
- loaded_apk->resources_asset_->getLength());
- if (data.data() == nullptr || data.empty()) {
+ const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
+ const size_t length = loaded_apk->resources_asset_->getLength();
+ if (!data || length == 0) {
LOG(ERROR) << "Failed to read '" << kResourcesArsc << "' data in APK '" << path << "'.";
return {};
}
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, loaded_apk->loaded_idmap_.get(),
+ loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, loaded_apk->loaded_idmap_.get(),
property_flags);
if (!loaded_apk->loaded_arsc_) {
LOG(ERROR) << "Failed to load '" << kResourcesArsc << "' in APK '" << path << "'.";
@@ -525,15 +518,15 @@
new ApkAssets(std::move(assets), path, last_mod_time, property_flags));
loaded_apk->resources_asset_ = std::move(resources_asset);
- const StringPiece data(
- reinterpret_cast<const char*>(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/)),
- loaded_apk->resources_asset_->getLength());
- if (data.data() == nullptr || data.empty()) {
+ const auto data = loaded_apk->resources_asset_->getIncFsBuffer(true /* aligned */);
+ const size_t length = loaded_apk->resources_asset_->getLength();
+ if (!data || length == 0) {
LOG(ERROR) << "Failed to read resources table data in '" << path << "'.";
return {};
}
- loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, nullptr, property_flags);
+ loaded_apk->loaded_arsc_ = LoadedArsc::Load(data, length, nullptr /* loaded_idmap */,
+ property_flags);
if (loaded_apk->loaded_arsc_ == nullptr) {
LOG(ERROR) << "Failed to read resources table in '" << path << "'.";
return {};
@@ -550,7 +543,6 @@
}
return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) &&
last_mod_time_ == getFileModDate(path_.c_str());
-
}
} // namespace android
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index cd30c18..4fbe4a3 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -298,34 +298,18 @@
/*
* Create a new Asset from a memory mapping.
*/
-/*static*/ Asset* Asset::createFromUncompressedMap(FileMap* dataMap, AccessMode mode)
+/*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(incfs::IncFsFileMap&& dataMap,
+ AccessMode mode,
+ base::unique_fd fd)
{
- _FileAsset* pAsset;
- status_t result;
+ auto pAsset = util::make_unique<_FileAsset>();
- pAsset = new _FileAsset;
- result = pAsset->openChunk(dataMap, base::unique_fd(-1));
- if (result != NO_ERROR) {
- delete pAsset;
- return NULL;
- }
-
- pAsset->mAccessMode = mode;
- return pAsset;
-}
-
-/*static*/ std::unique_ptr<Asset> Asset::createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
- base::unique_fd fd, AccessMode mode)
-{
- std::unique_ptr<_FileAsset> pAsset = util::make_unique<_FileAsset>();
-
- status_t result = pAsset->openChunk(dataMap.get(), std::move(fd));
+ status_t result = pAsset->openChunk(std::move(dataMap), std::move(fd));
if (result != NO_ERROR) {
return NULL;
}
// We succeeded, so relinquish control of dataMap
- (void) dataMap.release();
pAsset->mAccessMode = mode;
return std::move(pAsset);
}
@@ -333,35 +317,18 @@
/*
* Create a new Asset from compressed data in a memory mapping.
*/
-/*static*/ Asset* Asset::createFromCompressedMap(FileMap* dataMap,
- size_t uncompressedLen, AccessMode mode)
+/*static*/ std::unique_ptr<Asset> Asset::createFromCompressedMap(incfs::IncFsFileMap&& dataMap,
+ size_t uncompressedLen,
+ AccessMode mode)
{
- _CompressedAsset* pAsset;
- status_t result;
+ auto pAsset = util::make_unique<_CompressedAsset>();
- pAsset = new _CompressedAsset;
- result = pAsset->openChunk(dataMap, uncompressedLen);
- if (result != NO_ERROR) {
- delete pAsset;
- return NULL;
- }
-
- pAsset->mAccessMode = mode;
- return pAsset;
-}
-
-/*static*/ std::unique_ptr<Asset> Asset::createFromCompressedMap(std::unique_ptr<FileMap> dataMap,
- size_t uncompressedLen, AccessMode mode)
-{
- std::unique_ptr<_CompressedAsset> pAsset = util::make_unique<_CompressedAsset>();
-
- status_t result = pAsset->openChunk(dataMap.get(), uncompressedLen);
+ status_t result = pAsset->openChunk(std::move(dataMap), uncompressedLen);
if (result != NO_ERROR) {
return NULL;
}
// We succeeded, so relinquish control of dataMap
- (void) dataMap.release();
pAsset->mAccessMode = mode;
return std::move(pAsset);
}
@@ -414,7 +381,7 @@
* Constructor.
*/
_FileAsset::_FileAsset(void)
- : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mMap(NULL), mBuf(NULL)
+ : mStart(0), mLength(0), mOffset(0), mFp(NULL), mFileName(NULL), mFd(-1), mBuf(NULL)
{
// Register the Asset with the global list here after it is fully constructed and its
// vtable pointer points to this concrete type. b/31113965
@@ -441,7 +408,7 @@
status_t _FileAsset::openChunk(const char* fileName, int fd, off64_t offset, size_t length)
{
assert(mFp == NULL); // no reopen
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(fd >= 0);
assert(offset >= 0);
@@ -484,15 +451,15 @@
/*
* Create the chunk from the map.
*/
-status_t _FileAsset::openChunk(FileMap* dataMap, base::unique_fd fd)
+status_t _FileAsset::openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd)
{
assert(mFp == NULL); // no reopen
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(dataMap != NULL);
- mMap = dataMap;
+ mMap = std::move(dataMap);
mStart = -1; // not used
- mLength = dataMap->getDataLength();
+ mLength = mMap->length();
mFd = std::move(fd);
assert(mOffset == 0);
@@ -528,10 +495,15 @@
if (!count)
return 0;
- if (mMap != NULL) {
+ if (mMap.has_value()) {
/* copy from mapped area */
//printf("map read\n");
- memcpy(buf, (char*)mMap->getDataPtr() + mOffset, count);
+ const auto readPos = mMap->data().offset(mOffset).convert<char>();
+ if (!readPos.verify(count)) {
+ return -1;
+ }
+
+ memcpy(buf, readPos.unsafe_ptr(), count);
actual = count;
} else if (mBuf != NULL) {
/* copy from buffer */
@@ -594,10 +566,6 @@
*/
void _FileAsset::close(void)
{
- if (mMap != NULL) {
- delete mMap;
- mMap = NULL;
- }
if (mBuf != NULL) {
delete[] mBuf;
mBuf = NULL;
@@ -624,16 +592,21 @@
* level and we'd be using a different object, but we didn't, so we
* deal with it here.
*/
-const void* _FileAsset::getBuffer(bool wordAligned)
+const void* _FileAsset::getBuffer(bool aligned)
+{
+ return getIncFsBuffer(aligned).unsafe_ptr();
+}
+
+incfs::map_ptr<void> _FileAsset::getIncFsBuffer(bool aligned)
{
/* subsequent requests just use what we did previously */
if (mBuf != NULL)
return mBuf;
- if (mMap != NULL) {
- if (!wordAligned) {
- return mMap->getDataPtr();
+ if (mMap.has_value()) {
+ if (!aligned) {
+ return mMap->data();
}
- return ensureAlignment(mMap);
+ return ensureAlignment(*mMap);
}
assert(mFp != NULL);
@@ -671,47 +644,44 @@
mBuf = buf;
return mBuf;
} else {
- FileMap* map;
-
- map = new FileMap;
- if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
- delete map;
+ incfs::IncFsFileMap map;
+ if (!map.Create(fileno(mFp), mStart, mLength, NULL /* file_name */ )) {
return NULL;
}
ALOGV(" getBuffer: mapped\n");
- mMap = map;
- if (!wordAligned) {
- return mMap->getDataPtr();
+ mMap = std::move(map);
+ if (!aligned) {
+ return mMap->data();
}
- return ensureAlignment(mMap);
+ return ensureAlignment(*mMap);
}
}
int _FileAsset::openFileDescriptor(off64_t* outStart, off64_t* outLength) const
{
- if (mMap != NULL) {
+ if (mMap.has_value()) {
if (mFd.ok()) {
- *outStart = mMap->getDataOffset();
- *outLength = mMap->getDataLength();
- const int fd = dup(mFd);
- if (fd < 0) {
- ALOGE("Unable to dup fd (%d).", mFd.get());
- return -1;
- }
- lseek64(fd, 0, SEEK_SET);
- return fd;
+ *outStart = mMap->offset();
+ *outLength = mMap->length();
+ const int fd = dup(mFd);
+ if (fd < 0) {
+ ALOGE("Unable to dup fd (%d).", mFd.get());
+ return -1;
+ }
+ lseek64(fd, 0, SEEK_SET);
+ return fd;
}
- const char* fname = mMap->getFileName();
+ const char* fname = mMap->file_name();
if (fname == NULL) {
fname = mFileName;
}
if (fname == NULL) {
return -1;
}
- *outStart = mMap->getDataOffset();
- *outLength = mMap->getDataLength();
+ *outStart = mMap->offset();
+ *outLength = mMap->length();
return open(fname, O_RDONLY | O_BINARY);
}
if (mFileName == NULL) {
@@ -722,16 +692,21 @@
return open(mFileName, O_RDONLY | O_BINARY);
}
-const void* _FileAsset::ensureAlignment(FileMap* map)
+incfs::map_ptr<void> _FileAsset::ensureAlignment(const incfs::IncFsFileMap& map)
{
- void* data = map->getDataPtr();
- if ((((size_t)data)&0x3) == 0) {
+ const auto data = map.data();
+ if (util::IsFourByteAligned(data)) {
// We can return this directly if it is aligned on a word
// boundary.
ALOGV("Returning aligned FileAsset %p (%s).", this,
getAssetSource());
return data;
}
+
+ if (!data.convert<uint8_t>().verify(mLength)) {
+ return NULL;
+ }
+
// If not aligned on a word boundary, then we need to copy it into
// our own buffer.
ALOGV("Copying FileAsset %p (%s) to buffer size %d to make it aligned.", this,
@@ -741,7 +716,8 @@
ALOGE("alloc of %ld bytes failed\n", (long) mLength);
return NULL;
}
- memcpy(buf, data, mLength);
+
+ memcpy(buf, data.unsafe_ptr(), mLength);
mBuf = buf;
return buf;
}
@@ -757,7 +733,7 @@
*/
_CompressedAsset::_CompressedAsset(void)
: mStart(0), mCompressedLen(0), mUncompressedLen(0), mOffset(0),
- mMap(NULL), mFd(-1), mZipInflater(NULL), mBuf(NULL)
+ mFd(-1), mZipInflater(NULL), mBuf(NULL)
{
// Register the Asset with the global list here after it is fully constructed and its
// vtable pointer points to this concrete type. b/31113965
@@ -786,7 +762,7 @@
int compressionMethod, size_t uncompressedLen, size_t compressedLen)
{
assert(mFd < 0); // no re-open
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(fd >= 0);
assert(offset >= 0);
assert(compressedLen > 0);
@@ -815,20 +791,20 @@
*
* Nothing is expanded until the first read call.
*/
-status_t _CompressedAsset::openChunk(FileMap* dataMap, size_t uncompressedLen)
+status_t _CompressedAsset::openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen)
{
assert(mFd < 0); // no re-open
- assert(mMap == NULL);
+ assert(!mMap.has_value());
assert(dataMap != NULL);
- mMap = dataMap;
+ mMap = std::move(dataMap);
mStart = -1; // not used
- mCompressedLen = dataMap->getDataLength();
+ mCompressedLen = mMap->length();
mUncompressedLen = uncompressedLen;
assert(mOffset == 0);
if (uncompressedLen > StreamingZipInflater::OUTPUT_CHUNK_SIZE) {
- mZipInflater = new StreamingZipInflater(dataMap, uncompressedLen);
+ mZipInflater = new StreamingZipInflater(&(*mMap), uncompressedLen);
}
return NO_ERROR;
}
@@ -901,11 +877,6 @@
*/
void _CompressedAsset::close(void)
{
- if (mMap != NULL) {
- delete mMap;
- mMap = NULL;
- }
-
delete[] mBuf;
mBuf = NULL;
@@ -940,8 +911,8 @@
goto bail;
}
- if (mMap != NULL) {
- if (!ZipUtils::inflateToBuffer(mMap->getDataPtr(), buf,
+ if (mMap.has_value()) {
+ if (!ZipUtils::inflateToBuffer(mMap->data(), buf,
mUncompressedLen, mCompressedLen))
goto bail;
} else {
@@ -976,3 +947,6 @@
return mBuf;
}
+incfs::map_ptr<void> _CompressedAsset::getIncFsBuffer(bool aligned) {
+ return incfs::map_ptr<void>(getBuffer(aligned));
+}
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index f7c8337..fb2b571 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -917,7 +917,7 @@
Asset* AssetManager::openAssetFromZipLocked(const ZipFileRO* pZipFile,
const ZipEntryRO entry, AccessMode mode, const String8& entryName)
{
- Asset* pAsset = NULL;
+ std::unique_ptr<Asset> pAsset;
// TODO: look for previously-created shared memory slice?
uint16_t method;
@@ -932,28 +932,28 @@
return NULL;
}
- FileMap* dataMap = pZipFile->createEntryFileMap(entry);
- if (dataMap == NULL) {
+ std::optional<incfs::IncFsFileMap> dataMap = pZipFile->createEntryIncFsFileMap(entry);
+ if (!dataMap.has_value()) {
ALOGW("create map from entry failed\n");
return NULL;
}
if (method == ZipFileRO::kCompressStored) {
- pAsset = Asset::createFromUncompressedMap(dataMap, mode);
+ pAsset = Asset::createFromUncompressedMap(std::move(*dataMap), mode);
ALOGV("Opened uncompressed entry %s in zip %s mode %d: %p", entryName.string(),
- dataMap->getFileName(), mode, pAsset);
+ dataMap->file_name(), mode, pAsset.get());
} else {
- pAsset = Asset::createFromCompressedMap(dataMap,
+ pAsset = Asset::createFromCompressedMap(std::move(*dataMap),
static_cast<size_t>(uncompressedLen), mode);
ALOGV("Opened compressed entry %s in zip %s mode %d: %p", entryName.string(),
- dataMap->getFileName(), mode, pAsset);
+ dataMap->file_name(), mode, pAsset.get());
}
if (pAsset == NULL) {
/* unexpected */
ALOGW("create from segment failed\n");
}
- return pAsset;
+ return pAsset.release();
}
/*
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 99dd313..a545b3d 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -38,9 +38,43 @@
namespace android {
+namespace {
+
+using EntryValue = std::variant<Res_value, incfs::verified_map_ptr<ResTable_map_entry>>;
+
+base::expected<EntryValue, IOError> GetEntryValue(
+ incfs::verified_map_ptr<ResTable_entry> table_entry) {
+ const uint16_t entry_size = dtohs(table_entry->size);
+
+ // Check if the entry represents a bag value.
+ if (entry_size >= sizeof(ResTable_map_entry) &&
+ (dtohs(table_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
+ const auto map_entry = table_entry.convert<ResTable_map_entry>();
+ if (!map_entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return map_entry.verified();
+ }
+
+ // The entry represents a non-bag value.
+ const auto entry_value = table_entry.offset(entry_size).convert<Res_value>();
+ if (!entry_value) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ Res_value value;
+ value.copyFrom_dtoh(entry_value.value());
+ return value;
+}
+
+} // namespace
+
struct FindEntryResult {
- // A pointer to the value of the resource table entry.
- std::variant<Res_value, const ResTable_map_entry*> entry;
+ // The cookie representing the ApkAssets in which the value resides.
+ ApkAssetsCookie cookie;
+
+ // The value of the resource table entry. Either an android::Res_value for non-bag types or an
+ // incfs::verified_map_ptr<ResTable_map_entry> for bag types.
+ EntryValue entry;
// The configuration for which the resulting entry was defined. This is already swapped to host
// endianness.
@@ -265,7 +299,7 @@
}
const PackageGroup& package_group = package_groups_[idx];
- if (package_group.packages_.size() == 0) {
+ if (package_group.packages_.empty()) {
return nullptr;
}
@@ -310,14 +344,14 @@
for (auto it = loaded_package->begin(); it != loaded_package->end(); it++) {
const OverlayableInfo* info = loaded_package->GetOverlayableInfo(*it);
if (info != nullptr) {
- ResourceName res_name;
- if (!GetResourceName(*it, &res_name)) {
+ auto res_name = GetResourceName(*it);
+ if (!res_name.has_value()) {
ANDROID_LOG(ERROR) << base::StringPrintf(
"Unable to retrieve name of overlayable resource 0x%08x", *it);
return false;
}
- const std::string name = ToFormattedResourceString(&res_name);
+ const std::string name = ToFormattedResourceString(*res_name);
output.append(base::StringPrintf(
"resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
@@ -365,8 +399,8 @@
return non_system_overlays;
}
-std::set<ResTable_config> AssetManager2::GetResourceConfigurations(bool exclude_system,
- bool exclude_mipmap) const {
+base::expected<std::set<ResTable_config>, IOError> AssetManager2::GetResourceConfigurations(
+ bool exclude_system, bool exclude_mipmap) const {
ATRACE_NAME("AssetManager::GetResourceConfigurations");
const auto non_system_overlays =
(exclude_system) ? GetNonSystemOverlayPaths() : std::set<std::string>();
@@ -386,7 +420,10 @@
continue;
}
- package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+ auto result = package.loaded_package_->CollectConfigurations(exclude_mipmap, &configurations);
+ if (UNLIKELY(!result.has_value())) {
+ return base::unexpected(result.error());
+ }
}
}
return configurations;
@@ -501,11 +538,11 @@
return apk_assets_[cookie]->GetAssetsProvider()->Open(filename, mode);
}
-ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
- bool /*stop_at_first_match*/,
- bool ignore_configuration,
- FindEntryResult* out_entry) const {
- if (resource_resolution_logging_enabled_) {
+base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntry(
+ uint32_t resid, uint16_t density_override, bool stop_at_first_match,
+ bool ignore_configuration) const {
+ const bool logging_enabled = resource_resolution_logging_enabled_;
+ if (UNLIKELY(logging_enabled)) {
// Clear the last logged resource resolution.
ResetResourceResolution();
last_resolution_.resid = resid;
@@ -523,94 +560,96 @@
}
// Retrieve the package group from the package id of the resource id.
- if (!is_valid_resid(resid)) {
+ if (UNLIKELY(!is_valid_resid(resid))) {
LOG(ERROR) << base::StringPrintf("Invalid ID 0x%08x.", resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
const uint32_t package_id = get_package_id(resid);
const uint8_t type_idx = get_type_id(resid) - 1;
const uint16_t entry_idx = get_entry_id(resid);
uint8_t package_idx = package_ids_[package_id];
- if (package_idx == 0xff) {
+ if (UNLIKELY(package_idx == 0xff)) {
ANDROID_LOG(ERROR) << base::StringPrintf("No package ID %02x found for ID 0x%08x.",
package_id, resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
const PackageGroup& package_group = package_groups_[package_idx];
- ApkAssetsCookie cookie = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
- false /* stop_at_first_match */,
- ignore_configuration, out_entry);
- if (UNLIKELY(cookie == kInvalidCookie)) {
- return kInvalidCookie;
+ auto result = FindEntryInternal(package_group, type_idx, entry_idx, *desired_config,
+ stop_at_first_match, ignore_configuration);
+ if (UNLIKELY(!result.has_value())) {
+ return base::unexpected(result.error());
}
- if (!apk_assets_[cookie]->IsLoader()) {
+ if (!stop_at_first_match && !ignore_configuration && !apk_assets_[result->cookie]->IsLoader()) {
for (const auto& id_map : package_group.overlays_) {
auto overlay_entry = id_map.overlay_res_maps_.Lookup(resid);
if (!overlay_entry) {
// No id map entry exists for this target resource.
continue;
- } else if (overlay_entry.IsInlineValue()) {
+ }
+ if (overlay_entry.IsInlineValue()) {
// The target resource is overlaid by an inline value not represented by a resource.
- out_entry->entry = overlay_entry.GetInlineValue();
- out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
- cookie = id_map.cookie;
+ result->entry = overlay_entry.GetInlineValue();
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+ result->cookie = id_map.cookie;
continue;
}
- FindEntryResult overlay_result;
- ApkAssetsCookie overlay_cookie = FindEntry(overlay_entry.GetResourceId(), density_override,
- false /* stop_at_first_match */,
- ignore_configuration, &overlay_result);
- if (UNLIKELY(overlay_cookie == kInvalidCookie)) {
+ auto overlay_result = FindEntry(overlay_entry.GetResourceId(), density_override,
+ false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(overlay_result))) {
+ return base::unexpected(overlay_result.error());
+ }
+ if (!overlay_result.has_value()) {
continue;
}
- if (!overlay_result.config.isBetterThan(out_entry->config, desired_config)
- && overlay_result.config.compare(out_entry->config) != 0) {
+ if (!overlay_result->config.isBetterThan(result->config, desired_config)
+ && overlay_result->config.compare(result->config) != 0) {
// The configuration of the entry for the overlay must be equal to or better than the target
// configuration to be chosen as the better value.
continue;
}
- cookie = overlay_cookie;
- out_entry->entry = overlay_result.entry;
- out_entry->config = overlay_result.config;
- out_entry->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
- if (resource_resolution_logging_enabled_) {
+ result->cookie = overlay_result->cookie;
+ result->entry = overlay_result->entry;
+ result->config = overlay_result->config;
+ result->dynamic_ref_table = id_map.overlay_res_maps_.GetOverlayDynamicRefTable();
+
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(
- Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result.config.toString(),
- overlay_result.package_name});
+ Resolution::Step{Resolution::Step::Type::OVERLAID, overlay_result->config.toString(),
+ overlay_result->package_name});
}
}
}
- if (resource_resolution_logging_enabled_) {
- last_resolution_.cookie = cookie;
- last_resolution_.type_string_ref = out_entry->type_string_ref;
- last_resolution_.entry_string_ref = out_entry->entry_string_ref;
+ if (UNLIKELY(logging_enabled)) {
+ last_resolution_.cookie = result->cookie;
+ last_resolution_.type_string_ref = result->type_string_ref;
+ last_resolution_.entry_string_ref = result->entry_string_ref;
}
- return cookie;
+ return result;
}
-ApkAssetsCookie AssetManager2::FindEntryInternal(const PackageGroup& package_group,
- uint8_t type_idx, uint16_t entry_idx,
- const ResTable_config& desired_config,
- bool /*stop_at_first_match*/,
- bool ignore_configuration,
- FindEntryResult* out_entry) const {
+base::expected<FindEntryResult, NullOrIOError> AssetManager2::FindEntryInternal(
+ const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
+ const ResTable_config& desired_config, bool stop_at_first_match,
+ bool ignore_configuration) const {
+ const bool logging_enabled = resource_resolution_logging_enabled_;
ApkAssetsCookie best_cookie = kInvalidCookie;
const LoadedPackage* best_package = nullptr;
- const ResTable_type* best_type = nullptr;
+ incfs::verified_map_ptr<ResTable_type> best_type;
const ResTable_config* best_config = nullptr;
ResTable_config best_config_copy;
- uint32_t best_offset = 0u;
- uint32_t type_flags = 0u;
+ uint32_t best_offset = 0U;
+ uint32_t type_flags = 0U;
- Resolution::Step::Type resolution_type = Resolution::Step::Type::NO_ENTRY;
+ auto resolution_type = Resolution::Step::Type::NO_ENTRY;
std::vector<Resolution::Step> resolution_steps;
// If desired_config is the same as the set configuration, then we can use our filtered list
@@ -630,17 +669,20 @@
continue;
}
+ auto entry_flags = type_spec->GetFlagsForEntryIndex(entry_idx);
+ if (UNLIKELY(!entry_flags)) {
+ return base::unexpected(entry_flags.error());
+ }
+ type_flags |= entry_flags.value();
+
// If the package is an overlay or custom loader,
// then even configurations that are the same MUST be chosen.
const bool package_is_loader = loaded_package->IsCustomLoader();
- type_flags |= type_spec->GetFlagsForEntryIndex(entry_idx);
if (use_fast_path) {
const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx];
- const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations;
- const size_t type_count = candidate_configs.size();
- for (uint32_t i = 0; i < type_count; i++) {
- const ResTable_config& this_config = candidate_configs[i];
+ for (const auto& type_config : filtered_group.type_configs) {
+ const ResTable_config& this_config = type_config.config;
// We can skip calling ResTable_config::match() because we know that all candidate
// configurations that do NOT match have been filtered-out.
@@ -652,7 +694,7 @@
} else if (package_is_loader && this_config.compare(*best_config) == 0) {
resolution_type = Resolution::Step::Type::OVERLAID_LOADER;
} else {
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
resolution_type = (package_is_loader) ? Resolution::Step::Type::SKIPPED_LOADER
: Resolution::Step::Type::SKIPPED;
resolution_steps.push_back(Resolution::Step{resolution_type,
@@ -664,10 +706,13 @@
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const ResTable_type* type = filtered_group.types[i];
- const uint32_t offset = LoadedPackage::GetEntryOffset(type, entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
- if (resource_resolution_logging_enabled_) {
+ const auto& type = type_config.type;
+ const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
+ if (UNLIKELY(IsIOError(offset))) {
+ return base::unexpected(offset.error());
+ }
+ if (!offset.has_value()) {
+ if (UNLIKELY(logging_enabled)) {
if (package_is_loader) {
resolution_type = Resolution::Step::Type::NO_ENTRY_LOADER;
} else {
@@ -684,9 +729,9 @@
best_package = loaded_package;
best_type = type;
best_config = &this_config;
- best_offset = offset;
+ best_offset = offset.value();
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{resolution_type,
this_config.toString(),
&loaded_package->GetPackageName()});
@@ -700,10 +745,11 @@
// ResTable_config, we must copy it.
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config this_config{};
+ const incfs::verified_map_ptr<ResTable_type>& type = *iter;
+ ResTable_config this_config{};
if (!ignore_configuration) {
- this_config.copyFromDtoH((*iter)->config);
+ this_config.copyFromDtoH(type->config);
if (!this_config.match(desired_config)) {
continue;
}
@@ -722,24 +768,27 @@
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
- const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, entry_idx);
- if (offset == ResTable_type::NO_ENTRY) {
+ const auto offset = LoadedPackage::GetEntryOffset(type, entry_idx);
+ if (UNLIKELY(IsIOError(offset))) {
+ return base::unexpected(offset.error());
+ }
+ if (!offset.has_value()) {
continue;
}
best_cookie = cookie;
best_package = loaded_package;
- best_type = *iter;
+ best_type = type;
best_config_copy = this_config;
best_config = &best_config_copy;
- best_offset = offset;
+ best_offset = offset.value();
- if (ignore_configuration) {
+ if (stop_at_first_match) {
// Any configuration will suffice, so break.
break;
}
- if (resource_resolution_logging_enabled_) {
+ if (UNLIKELY(logging_enabled)) {
last_resolution_.steps.push_back(Resolution::Step{resolution_type,
this_config.toString(),
&loaded_package->GetPackageName()});
@@ -749,36 +798,35 @@
}
if (UNLIKELY(best_cookie == kInvalidCookie)) {
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
- const ResTable_entry* best_entry = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
- if (UNLIKELY(best_entry == nullptr)) {
- return kInvalidCookie;
+ auto best_entry_result = LoadedPackage::GetEntryFromOffset(best_type, best_offset);
+ if (!best_entry_result.has_value()) {
+ return base::unexpected(best_entry_result.error());
}
- const uint16_t entry_size = dtohs(best_entry->size);
- if (entry_size >= sizeof(ResTable_map_entry) &&
- (dtohs(best_entry->flags) & ResTable_entry::FLAG_COMPLEX)) {
- // The entry represents a bag/map.
- out_entry->entry = reinterpret_cast<const ResTable_map_entry*>(best_entry);
- } else {
- // The entry represents a value.
- Res_value value;
- value.copyFrom_dtoh(*reinterpret_cast<const Res_value*>(
- reinterpret_cast<const uint8_t*>(best_entry) + entry_size));
- out_entry->entry = value;
+ const incfs::map_ptr<ResTable_entry> best_entry = *best_entry_result;
+ if (!best_entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- out_entry->config = *best_config;
- out_entry->type_flags = type_flags;
- out_entry->package_name = &best_package->GetPackageName();
- out_entry->type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1);
- out_entry->entry_string_ref =
- StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index);
- out_entry->dynamic_ref_table = package_group.dynamic_ref_table.get();
+ const auto entry = GetEntryValue(best_entry.verified());
+ if (!entry.has_value()) {
+ return base::unexpected(entry.error());
+ }
- return best_cookie;
+ return FindEntryResult{
+ .cookie = best_cookie,
+ .entry = *entry,
+ .config = *best_config,
+ .type_flags = type_flags,
+ .package_name = &best_package->GetPackageName(),
+ .type_string_ref = StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1),
+ .entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(),
+ best_entry->key.index),
+ .dynamic_ref_table = package_group.dynamic_ref_table.get(),
+ };
}
void AssetManager2::ResetResourceResolution() const {
@@ -799,30 +847,28 @@
std::string AssetManager2::GetLastResourceResolution() const {
if (!resource_resolution_logging_enabled_) {
LOG(ERROR) << "Must enable resource resolution logging before getting path.";
- return std::string();
+ return {};
}
auto cookie = last_resolution_.cookie;
if (cookie == kInvalidCookie) {
LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path.";
- return std::string();
+ return {};
}
uint32_t resid = last_resolution_.resid;
std::vector<Resolution::Step>& steps = last_resolution_.steps;
-
- ResourceName resource_name;
std::string resource_name_string;
const LoadedPackage* package =
apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid));
if (package != nullptr) {
- ToResourceName(last_resolution_.type_string_ref,
- last_resolution_.entry_string_ref,
- package->GetPackageName(),
- &resource_name);
- resource_name_string = ToFormattedResourceString(&resource_name);
+ auto resource_name = ToResourceName(last_resolution_.type_string_ref,
+ last_resolution_.entry_string_ref,
+ package->GetPackageName());
+ resource_name_string = resource_name.has_value() ?
+ ToFormattedResourceString(resource_name.value()) : "<unknown>";
}
std::stringstream log_stream;
@@ -875,200 +921,208 @@
return log_stream.str();
}
-bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- true /* stop_at_first_match */,
- true /* ignore_configuration */, &entry);
- if (cookie == kInvalidCookie) {
- return false;
+base::expected<AssetManager2::ResourceName, NullOrIOError> AssetManager2::GetResourceName(
+ uint32_t resid) const {
+ auto result = FindEntry(resid, 0u /* density_override */, true /* stop_at_first_match */,
+ true /* ignore_configuration */);
+ if (!result.has_value()) {
+ return base::unexpected(result.error());
}
- return ToResourceName(entry.type_string_ref,
- entry.entry_string_ref,
- *entry.package_name,
- out_name);
+ return ToResourceName(result->type_string_ref,
+ result->entry_string_ref,
+ *result->package_name);
}
-bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- false /* stop_at_first_match */,
- true /* ignore_configuration */, &entry);
- if (cookie != kInvalidCookie) {
- *out_flags = entry.type_flags;
- return true;
- }
- return false;
-}
-
-ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
- uint16_t density_override, Res_value* out_value,
- ResTable_config* out_selected_config,
- uint32_t* out_flags) const {
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, density_override, false /* stop_at_first_match */,
- false /* ignore_configuration */, &entry);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
+base::expected<AssetManager2::SelectedValue, NullOrIOError> AssetManager2::GetResource(
+ uint32_t resid, bool may_be_bag, uint16_t density_override) const {
+ auto result = FindEntry(resid, density_override, false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (!result.has_value()) {
+ return base::unexpected(result.error());
}
- auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
+ auto result_map_entry = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&result->entry);
if (result_map_entry != nullptr) {
if (!may_be_bag) {
LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
- return kInvalidCookie;
+ return base::unexpected(std::nullopt);
}
// Create a reference since we can't represent this complex type as a Res_value.
- out_value->dataType = Res_value::TYPE_REFERENCE;
- out_value->data = resid;
- *out_selected_config = entry.config;
- *out_flags = entry.type_flags;
- return cookie;
+ return SelectedValue(Res_value::TYPE_REFERENCE, resid, result->cookie, result->type_flags,
+ resid, result->config);
}
// Convert the package ID to the runtime assigned package ID.
- *out_value = std::get<Res_value>(entry.entry);
- entry.dynamic_ref_table->lookupResourceValue(out_value);
+ Res_value value = std::get<Res_value>(result->entry);
+ result->dynamic_ref_table->lookupResourceValue(&value);
- *out_selected_config = entry.config;
- *out_flags = entry.type_flags;
- return cookie;
+ return SelectedValue(value.dataType, value.data, result->cookie, result->type_flags,
+ resid, result->config);
}
-ApkAssetsCookie AssetManager2::ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config,
- uint32_t* in_out_flags,
- uint32_t* out_last_reference) const {
- constexpr const int kMaxIterations = 20;
+base::expected<std::monostate, NullOrIOError> AssetManager2::ResolveReference(
+ AssetManager2::SelectedValue& value, bool cache_value) const {
+ if (value.type != Res_value::TYPE_REFERENCE || value.data == 0U) {
+ // Not a reference. Nothing to do.
+ return {};
+ }
- for (size_t iteration = 0u; in_out_value->dataType == Res_value::TYPE_REFERENCE &&
- in_out_value->data != 0u && iteration < kMaxIterations;
- iteration++) {
- *out_last_reference = in_out_value->data;
- uint32_t new_flags = 0u;
- cookie = GetResource(in_out_value->data, true /*may_be_bag*/, 0u /*density_override*/,
- in_out_value, in_out_selected_config, &new_flags);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
- }
- if (in_out_flags != nullptr) {
- *in_out_flags |= new_flags;
- }
- if (*out_last_reference == in_out_value->data) {
- // This reference can't be resolved, so exit now and let the caller deal with it.
- return cookie;
+ const uint32_t original_flags = value.flags;
+ const uint32_t original_resid = value.data;
+ if (cache_value) {
+ auto cached_value = cached_resolved_values_.find(value.data);
+ if (cached_value != cached_resolved_values_.end()) {
+ value = cached_value->second;
+ value.flags |= original_flags;
+ return {};
}
}
- return cookie;
+
+ uint32_t combined_flags = 0U;
+ uint32_t resolve_resid = original_resid;
+ constexpr const uint32_t kMaxIterations = 20;
+ for (uint32_t i = 0U;; i++) {
+ auto result = GetResource(resolve_resid, true /*may_be_bag*/);
+ if (!result.has_value()) {
+ value.resid = resolve_resid;
+ return base::unexpected(result.error());
+ }
+
+ // If resource resolution fails, the value should be set to the last reference that was able to
+ // be resolved successfully.
+ value = *result;
+ value.flags |= combined_flags;
+
+ if (result->type != Res_value::TYPE_REFERENCE ||
+ result->data == Res_value::DATA_NULL_UNDEFINED ||
+ result->data == resolve_resid || i == kMaxIterations) {
+ // This reference can't be resolved, so exit now and let the caller deal with it.
+ if (cache_value) {
+ cached_resolved_values_[original_resid] = value;
+ }
+
+ // Above value is cached without original_flags to ensure they don't get included in future
+ // queries that hit the cache
+ value.flags |= original_flags;
+ return {};
+ }
+
+ combined_flags = result->flags;
+ resolve_resid = result->data;
+ }
}
-const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) {
+const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) const {
auto cached_iter = cached_bag_resid_stacks_.find(resid);
if (cached_iter != cached_bag_resid_stacks_.end()) {
return cached_iter->second;
- } else {
- auto found_resids = std::vector<uint32_t>();
- GetBag(resid, found_resids);
- // Cache style stacks if they are not already cached.
- cached_bag_resid_stacks_[resid] = found_resids;
- return found_resids;
}
+
+ std::vector<uint32_t> found_resids;
+ GetBag(resid, found_resids);
+ cached_bag_resid_stacks_.emplace(resid, found_resids);
+ return found_resids;
}
-const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
- auto found_resids = std::vector<uint32_t>();
- auto bag = GetBag(resid, found_resids);
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::ResolveBag(
+ AssetManager2::SelectedValue& value) const {
+ if (UNLIKELY(value.type != Res_value::TYPE_REFERENCE)) {
+ return base::unexpected(std::nullopt);
+ }
- // Cache style stacks if they are not already cached.
- auto cached_iter = cached_bag_resid_stacks_.find(resid);
- if (cached_iter == cached_bag_resid_stacks_.end()) {
- cached_bag_resid_stacks_[resid] = found_resids;
+ auto bag = GetBag(value.data);
+ if (bag.has_value()) {
+ value.flags |= (*bag)->type_spec_flags;
}
return bag;
}
-static bool compare_bag_entries(const ResolvedBag::Entry& entry1,
- const ResolvedBag::Entry& entry2) {
- return entry1.key < entry2.key;
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(uint32_t resid) const {
+ std::vector<uint32_t> found_resids;
+ const auto bag = GetBag(resid, found_resids);
+ cached_bag_resid_stacks_.emplace(resid, found_resids);
+ return bag;
}
-const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
- auto cached_iter = cached_bags_.find(resid);
- if (cached_iter != cached_bags_.end()) {
+base::expected<const ResolvedBag*, NullOrIOError> AssetManager2::GetBag(
+ uint32_t resid, std::vector<uint32_t>& child_resids) const {
+ if (auto cached_iter = cached_bags_.find(resid); cached_iter != cached_bags_.end()) {
return cached_iter->second.get();
}
- FindEntryResult entry;
- ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
- false /* stop_at_first_match */,
- false /* ignore_configuration */,
- &entry);
- if (cookie == kInvalidCookie) {
- return nullptr;
+ auto entry = FindEntry(resid, 0u /* density_override */, false /* stop_at_first_match */,
+ false /* ignore_configuration */);
+ if (!entry.has_value()) {
+ return base::unexpected(entry.error());
}
- auto result_map_entry = std::get_if<const ResTable_map_entry*>(&entry.entry);
- if (result_map_entry == nullptr) {
+ auto entry_map = std::get_if<incfs::verified_map_ptr<ResTable_map_entry>>(&entry->entry);
+ if (entry_map == nullptr) {
// Not a bag, nothing to do.
- return nullptr;
+ return base::unexpected(std::nullopt);
}
- auto map = reinterpret_cast<const ResTable_map_entry*>(*result_map_entry);
- auto map_entry = reinterpret_cast<const ResTable_map*>(
- reinterpret_cast<const uint8_t*>(map) + map->size);
- const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
+ auto map = *entry_map;
+ auto map_entry = map.offset(dtohs(map->size)).convert<ResTable_map>();
+ const auto map_entry_end = map_entry + dtohl(map->count);
// Keep track of ids that have already been seen to prevent infinite loops caused by circular
- // dependencies between bags
+ // dependencies between bags.
child_resids.push_back(resid);
uint32_t parent_resid = dtohl(map->parent.ident);
- if (parent_resid == 0U || std::find(child_resids.begin(), child_resids.end(), parent_resid)
- != child_resids.end()) {
- // There is no parent or a circular dependency exist, meaning there is nothing to inherit and
- // we can do a simple copy of the entries in the map.
+ if (parent_resid == 0U ||
+ std::find(child_resids.begin(), child_resids.end(), parent_resid) != child_resids.end()) {
+ // There is no parent or a circular parental dependency exist, meaning there is nothing to
+ // inherit and we can do a simple copy of the entries in the map.
const size_t entry_count = map_entry_end - map_entry;
util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
bool sort_entries = false;
- ResolvedBag::Entry* new_entry = new_bag->entries;
- for (; map_entry != map_entry_end; ++map_entry) {
+ for (auto new_entry = new_bag->entries; map_entry != map_entry_end; ++map_entry) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
// Attributes, arrays, etc don't have a resource id as the name. They specify
// other data, which would be wrong to change via a lookup.
- if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
- new_entry->cookie = cookie;
+
+ new_entry->cookie = entry->cookie;
new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->style = resid;
new_entry->value.copyFrom_dtoh(map_entry->value);
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf(
"Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
new_entry->value.data, new_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
+
sort_entries = sort_entries ||
(new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
++new_entry;
}
if (sort_entries) {
- std::sort(new_bag->entries, new_bag->entries + entry_count, compare_bag_entries);
+ std::sort(new_bag->entries, new_bag->entries + entry_count,
+ [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
}
- new_bag->type_spec_flags = entry.type_flags;
+ new_bag->type_spec_flags = entry->type_flags;
new_bag->entry_count = static_cast<uint32_t>(entry_count);
ResolvedBag* result = new_bag.get();
cached_bags_[resid] = std::move(new_bag);
@@ -1076,54 +1130,58 @@
}
// In case the parent is a dynamic reference, resolve it.
- entry.dynamic_ref_table->lookupResourceId(&parent_resid);
+ entry->dynamic_ref_table->lookupResourceId(&parent_resid);
// Get the parent and do a merge of the keys.
- const ResolvedBag* parent_bag = GetBag(parent_resid, child_resids);
- if (parent_bag == nullptr) {
+ const auto parent_bag = GetBag(parent_resid, child_resids);
+ if (UNLIKELY(!parent_bag.has_value())) {
// Failed to get the parent that should exist.
LOG(ERROR) << base::StringPrintf("Failed to find parent 0x%08x of bag 0x%08x.", parent_resid,
resid);
- return nullptr;
+ return base::unexpected(parent_bag.error());
}
// Create the max possible entries we can make. Once we construct the bag,
// we will realloc to fit to size.
- const size_t max_count = parent_bag->entry_count + dtohl(map->count);
+ const size_t max_count = (*parent_bag)->entry_count + dtohl(map->count);
util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))))};
ResolvedBag::Entry* new_entry = new_bag->entries;
- const ResolvedBag::Entry* parent_entry = parent_bag->entries;
- const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
+ const ResolvedBag::Entry* parent_entry = (*parent_bag)->entries;
+ const ResolvedBag::Entry* const parent_entry_end = parent_entry + (*parent_bag)->entry_count;
// The keys are expected to be in sorted order. Merge the two bags.
bool sort_entries = false;
while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t child_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(child_key)) {
- if (entry.dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&child_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", child_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
if (child_key <= parent_entry->key) {
// Use the child key if it comes before the parent
// or is equal to the parent (overrides).
- new_entry->cookie = cookie;
+ new_entry->cookie = entry->cookie;
new_entry->key = child_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
new_entry->style = resid;
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf(
"Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.", new_entry->value.dataType,
new_entry->value.data, child_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
++map_entry;
} else {
@@ -1143,25 +1201,29 @@
// Finish the child entries if they exist.
while (map_entry != map_entry_end) {
+ if (UNLIKELY(!map_entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
uint32_t new_key = dtohl(map_entry->name.ident);
if (!is_internal_resid(new_key)) {
- if (entry.dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR) {
+ if (UNLIKELY(entry->dynamic_ref_table->lookupResourceId(&new_key) != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve key 0x%08x in bag 0x%08x.", new_key,
resid);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
}
- new_entry->cookie = cookie;
+ new_entry->cookie = entry->cookie;
new_entry->key = new_key;
new_entry->key_pool = nullptr;
new_entry->type_pool = nullptr;
new_entry->value.copyFrom_dtoh(map_entry->value);
new_entry->style = resid;
- status_t err = entry.dynamic_ref_table->lookupResourceValue(&new_entry->value);
- if (err != NO_ERROR) {
+ status_t err = entry->dynamic_ref_table->lookupResourceValue(&new_entry->value);
+ if (UNLIKELY(err != NO_ERROR)) {
LOG(ERROR) << base::StringPrintf("Failed to resolve value t=0x%02x d=0x%08x for key 0x%08x.",
new_entry->value.dataType, new_entry->value.data, new_key);
- return nullptr;
+ return base::unexpected(std::nullopt);
}
sort_entries = sort_entries ||
(new_entry != new_bag->entries && (new_entry->key < (new_entry - 1U)->key));
@@ -1185,11 +1247,12 @@
}
if (sort_entries) {
- std::sort(new_bag->entries, new_bag->entries + actual_count, compare_bag_entries);
+ std::sort(new_bag->entries, new_bag->entries + actual_count,
+ [](auto&& lhs, auto&& rhs) { return lhs.key < rhs.key; });
}
// Combine flags from the parent and our own bag.
- new_bag->type_spec_flags = entry.type_flags | parent_bag->type_spec_flags;
+ new_bag->type_spec_flags = entry->type_flags | (*parent_bag)->type_spec_flags;
new_bag->entry_count = static_cast<uint32_t>(actual_count);
ResolvedBag* result = new_bag.get();
cached_bags_[resid] = std::move(new_bag);
@@ -1208,16 +1271,16 @@
return true;
}
-uint32_t AssetManager2::GetResourceId(const std::string& resource_name,
- const std::string& fallback_type,
- const std::string& fallback_package) const {
+base::expected<uint32_t, NullOrIOError> AssetManager2::GetResourceId(
+ const std::string& resource_name, const std::string& fallback_type,
+ const std::string& fallback_package) const {
StringPiece package_name, type, entry;
if (!ExtractResourceName(resource_name, &package_name, &type, &entry)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
if (entry.empty()) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
if (package_name.empty()) {
@@ -1230,12 +1293,12 @@
std::u16string type16;
if (!Utf8ToUtf16(type, &type16)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
std::u16string entry16;
if (!Utf8ToUtf16(entry, &entry16)) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
const StringPiece16 kAttr16 = u"attr";
@@ -1249,20 +1312,24 @@
break;
}
- uint32_t resid = package->FindEntryByName(type16, entry16);
- if (resid == 0u && kAttr16 == type16) {
+ base::expected<uint32_t, NullOrIOError> resid = package->FindEntryByName(type16, entry16);
+ if (UNLIKELY(IsIOError(resid))) {
+ return base::unexpected(resid.error());
+ }
+
+ if (!resid.has_value() && kAttr16 == type16) {
// Private attributes in libraries (such as the framework) are sometimes encoded
// under the type '^attr-private' in order to leave the ID space of public 'attr'
// free for future additions. Check '^attr-private' for the same name.
resid = package->FindEntryByName(kAttrPrivate16, entry16);
}
- if (resid != 0u) {
- return fix_package_id(resid, package_group.dynamic_ref_table->mAssignedPackageId);
+ if (resid.has_value()) {
+ return fix_package_id(*resid, package_group.dynamic_ref_table->mAssignedPackageId);
}
}
}
- return 0u;
+ return base::unexpected(std::nullopt);
}
void AssetManager2::RebuildFilterList(bool filter_incompatible_configs) {
@@ -1282,8 +1349,7 @@
ResTable_config this_config;
this_config.copyFromDtoH((*iter)->config);
if (!filter_incompatible_configs || this_config.match(configuration_)) {
- group.configurations.push_back(this_config);
- group.types.push_back(*iter);
+ group.type_configs.push_back(TypeConfig{*iter, this_config});
}
}
});
@@ -1309,6 +1375,8 @@
++iter;
}
}
+
+ cached_resolved_values_.clear();
}
uint8_t AssetManager2::GetAssignedPackageId(const LoadedPackage* package) const {
@@ -1354,16 +1422,16 @@
std::array<util::unique_cptr<ThemeType>, kTypeCount> types;
};
-bool Theme::ApplyStyle(uint32_t resid, bool force) {
+base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
ATRACE_NAME("Theme::ApplyStyle");
- const ResolvedBag* bag = asset_manager_->GetBag(resid);
- if (bag == nullptr) {
- return false;
+ auto bag = asset_manager_->GetBag(resid);
+ if (!bag.has_value()) {
+ return base::unexpected(bag.error());
}
// Merge the flags from this style.
- type_spec_flags_ |= bag->type_spec_flags;
+ type_spec_flags_ |= (*bag)->type_spec_flags;
int last_type_idx = -1;
int last_package_idx = -1;
@@ -1373,14 +1441,14 @@
// Iterate backwards, because each bag is sorted in ascending key ID order, meaning we will only
// need to perform one resize per type.
using reverse_bag_iterator = std::reverse_iterator<const ResolvedBag::Entry*>;
- const auto bag_iter_end = reverse_bag_iterator(begin(bag));
- for (auto bag_iter = reverse_bag_iterator(end(bag)); bag_iter != bag_iter_end; ++bag_iter) {
- const uint32_t attr_resid = bag_iter->key;
+ const auto rbegin = reverse_bag_iterator(begin(*bag));
+ for (auto it = reverse_bag_iterator(end(*bag)); it != rbegin; ++it) {
+ const uint32_t attr_resid = it->key;
// If the resource ID passed in is not a style, the key can be some other identifier that is not
// a resource ID. We should fail fast instead of operating with strange resource IDs.
if (!is_valid_resid(attr_resid)) {
- return false;
+ return base::unexpected(std::nullopt);
}
// We don't use the 0-based index for the type so that we can avoid doing ID validation
@@ -1428,20 +1496,18 @@
ThemeEntry& entry = last_type->entries[entry_idx];
if (force || (entry.value.dataType == Res_value::TYPE_NULL &&
entry.value.data != Res_value::DATA_NULL_EMPTY)) {
- entry.cookie = bag_iter->cookie;
- entry.type_spec_flags |= bag->type_spec_flags;
- entry.value = bag_iter->value;
+ entry.cookie = it->cookie;
+ entry.type_spec_flags |= (*bag)->type_spec_flags;
+ entry.value = it->value;
}
}
- return true;
+ return {};
}
-ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
- uint32_t* out_flags) const {
+std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
+
int cnt = 20;
-
uint32_t type_spec_flags = 0u;
-
do {
const int package_idx = get_package_id(resid);
const Package* package = packages_[package_idx].get();
@@ -1461,43 +1527,42 @@
resid = entry.value.data;
continue;
}
- return kInvalidCookie;
+ return std::nullopt;
}
// @null is different than @empty.
if (entry.value.dataType == Res_value::TYPE_NULL &&
entry.value.data != Res_value::DATA_NULL_EMPTY) {
- return kInvalidCookie;
+ return std::nullopt;
}
- *out_value = entry.value;
- *out_flags = type_spec_flags;
- return entry.cookie;
+ return AssetManager2::SelectedValue(entry.value.dataType, entry.value.data, entry.cookie,
+ type_spec_flags, 0U /* resid */, {} /* config */);
}
}
}
break;
} while (true);
- return kInvalidCookie;
+ return std::nullopt;
}
-ApkAssetsCookie Theme::ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config,
- uint32_t* in_out_type_spec_flags,
- uint32_t* out_last_ref) const {
- if (in_out_value->dataType == Res_value::TYPE_ATTRIBUTE) {
- uint32_t new_flags;
- cookie = GetAttribute(in_out_value->data, in_out_value, &new_flags);
- if (cookie == kInvalidCookie) {
- return kInvalidCookie;
- }
-
- if (in_out_type_spec_flags != nullptr) {
- *in_out_type_spec_flags |= new_flags;
- }
+base::expected<std::monostate, NullOrIOError> Theme::ResolveAttributeReference(
+ AssetManager2::SelectedValue& value) const {
+ if (value.type != Res_value::TYPE_ATTRIBUTE) {
+ return asset_manager_->ResolveReference(value);
}
- return asset_manager_->ResolveReference(cookie, in_out_value, in_out_selected_config,
- in_out_type_spec_flags, out_last_ref);
+
+ std::optional<AssetManager2::SelectedValue> result = GetAttribute(value.data);
+ if (!result.has_value()) {
+ return base::unexpected(std::nullopt);
+ }
+
+ auto resolve_result = asset_manager_->ResolveReference(*result, true /* cache_value */);
+ if (resolve_result.has_value()) {
+ result->flags |= value.flags;
+ value = *result;
+ }
+ return resolve_result;
}
void Theme::Clear() {
@@ -1507,9 +1572,9 @@
}
}
-void Theme::SetTo(const Theme& o) {
+base::expected<std::monostate, IOError> Theme::SetTo(const Theme& o) {
if (this == &o) {
- return;
+ return {};
}
type_spec_flags_ = o.type_spec_flags_;
@@ -1560,10 +1625,8 @@
// Map the runtime package of the source apk asset to the destination apk asset.
if (src_asset->GetPath() == dest_asset->GetPath()) {
- const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
- src_asset->GetLoadedArsc()->GetPackages();
- const std::vector<std::unique_ptr<const LoadedPackage>>& dest_packages =
- dest_asset->GetLoadedArsc()->GetPackages();
+ const auto& src_packages = src_asset->GetLoadedArsc()->GetPackages();
+ const auto& dest_packages = dest_asset->GetLoadedArsc()->GetPackages();
SourceToDestinationRuntimePackageMap package_map;
@@ -1660,15 +1723,20 @@
int attribute_dest_package_id = p;
if (attribute_dest_package_id != 0x01) {
// Find the cookie of the attribute resource id in the source AssetManager
- FindEntryResult attribute_entry_result;
- ApkAssetsCookie attribute_cookie =
+ base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
true /* stop_at_first_match */,
- true /* ignore_configuration */,
- &attribute_entry_result);
+ true /* ignore_configuration */);
+ if (UNLIKELY(IsIOError(attribute_entry_result))) {
+ return base::unexpected(GetIOError(attribute_entry_result.error()));
+ }
+ if (!attribute_entry_result.has_value()) {
+ continue;
+ }
// Determine the package id of the attribute in the destination AssetManager.
- auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
+ auto attribute_package_map = src_asset_cookie_id_map.find(
+ attribute_entry_result->cookie);
if (attribute_package_map == src_asset_cookie_id_map.end()) {
continue;
}
@@ -1712,6 +1780,7 @@
}
}
}
+ return {};
}
void Theme::Dump() const {
diff --git a/libs/androidfw/AttributeResolution.cpp b/libs/androidfw/AttributeResolution.cpp
index e62fb61..c188712 100644
--- a/libs/androidfw/AttributeResolution.cpp
+++ b/libs/androidfw/AttributeResolution.cpp
@@ -24,9 +24,12 @@
#include "androidfw/AttributeFinder.h"
constexpr bool kDebugStyles = false;
+#define DEBUG_LOG(...) do { if (kDebugStyles) { ALOGI(__VA_ARGS__); } } while(0)
namespace android {
+namespace {
+
// Java asset cookies have 0 as an invalid cookie, but TypedArray expects < 0.
static uint32_t ApkAssetsCookieToJavaCookie(ApkAssetsCookie cookie) {
return cookie != kInvalidCookie ? static_cast<uint32_t>(cookie + 1) : static_cast<uint32_t>(-1);
@@ -36,8 +39,7 @@
: public BackTrackingAttributeFinder<XmlAttributeFinder, size_t> {
public:
explicit XmlAttributeFinder(const ResXMLParser* parser)
- : BackTrackingAttributeFinder(
- 0, parser != nullptr ? parser->getAttributeCount() : 0),
+ : BackTrackingAttributeFinder(0, parser != nullptr ? parser->getAttributeCount() : 0),
parser_(parser) {}
inline uint32_t GetAttribute(size_t index) const {
@@ -61,136 +63,149 @@
}
};
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_res,
- uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme,
- def_style_attr, def_style_res);
- }
-
- AssetManager2* assetmanager = theme->GetAssetManager();
- ResTable_config config;
- Res_value value;
-
- int indices_idx = 0;
-
- // Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
- if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_res = value.data;
+base::expected<const ResolvedBag*, NullOrIOError> GetStyleBag(Theme* theme,
+ uint32_t theme_attribute_resid,
+ uint32_t fallback_resid,
+ uint32_t* out_theme_flags) {
+ // Load the style from the attribute if specified.
+ if (theme_attribute_resid != 0U) {
+ std::optional<AssetManager2::SelectedValue> value = theme->GetAttribute(theme_attribute_resid);
+ if (value.has_value()) {
+ *out_theme_flags |= value->flags;
+ auto result = theme->GetAssetManager()->ResolveBag(*value);
+ if (result.has_value() || IsIOError(result)) {
+ return result;
}
}
}
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_res != 0) {
- default_style_bag = assetmanager->GetBag(def_style_res);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
+ // Fallback to loading the style from the resource id if specified.
+ if (fallback_resid != 0U) {
+ return theme->GetAssetManager()->GetBag(fallback_resid);
+ }
+
+ return base::unexpected(std::nullopt);
+}
+
+base::expected<const ResolvedBag*, NullOrIOError> GetXmlStyleBag(Theme* theme,
+ ResXMLParser* xml_parser,
+ uint32_t* out_theme_flags) {
+ if (xml_parser == nullptr) {
+ return base::unexpected(std::nullopt);
+ }
+
+ // Retrieve the style resource ID associated with the current XML tag's style attribute.
+ Res_value value;
+ const ssize_t idx = xml_parser->indexOfStyle();
+ if (idx < 0 || xml_parser->getAttributeValue(idx, &value) < 0) {
+ return base::unexpected(std::nullopt);
+ }
+
+ if (value.dataType == Res_value::TYPE_ATTRIBUTE) {
+ // Resolve the attribute with out theme.
+ if (std::optional<AssetManager2::SelectedValue> result = theme->GetAttribute(value.data)) {
+ *out_theme_flags |= result->flags;
+ return theme->GetAssetManager()->ResolveBag(*result);
}
}
- BagAttributeFinder def_style_attr_finder(default_style_bag);
+ if (value.dataType == Res_value::TYPE_REFERENCE) {
+ return theme->GetAssetManager()->GetBag(value.data);
+ }
+
+ return base::unexpected(std::nullopt);
+}
+
+} // namespace
+
+base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr,
+ uint32_t def_style_res, uint32_t* src_values,
+ size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values,
+ uint32_t* out_indices) {
+ DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x", theme, def_style_attr,
+ def_style_res);
+
+ int indices_idx = 0;
+ const AssetManager2* assetmanager = theme->GetAssetManager();
+
+ // Load default style from attribute or resource id, if specified...
+ uint32_t def_style_theme_flags = 0U;
+ const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_res,
+ &def_style_theme_flags);
+ if (UNLIKELY(IsIOError(default_style_bag))) {
+ return base::unexpected(GetIOError(default_style_bag.error()));
+ }
+
+ BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
-
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
- }
-
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
// Try to find a value for this attribute... we prioritize values
// coming from, first XML attributes, then XML style, then default
// style, and finally the theme.
// Retrieve the current input value if available.
+ AssetManager2::SelectedValue value{};
if (src_values_length > 0 && src_values[ii] != 0) {
- value.dataType = Res_value::TYPE_ATTRIBUTE;
+ value.type = Res_value::TYPE_ATTRIBUTE;
value.data = src_values[ii];
- if (kDebugStyles) {
- ALOGI("-> From values: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ DEBUG_LOG("-> From values: type=0x%x, data=0x%08x", value.type, value.data);
} else {
const ResolvedBag::Entry* const entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ value = AssetManager2::SelectedValue(*default_style_bag, *entry);
+ value.flags |= def_style_theme_flags;
+ DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x", value.type, value.data);
}
}
- uint32_t resid = 0;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ const auto result = theme->ResolveAttributeReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- if (new_cookie != kInvalidCookie) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ if (auto attr_value = theme->GetAttribute(cur_ident)) {
+ value = *attr_value;
+ DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
+
+ const auto result = assetmanager->ResolveReference(value, true /* cache_value */);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0) {
+ DEBUG_LOG("-> Setting to @null!");
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
- }
+ DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
if (out_indices != nullptr &&
- (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
- indices_idx++;
- out_indices[indices_idx] = ii;
+ (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
@@ -199,93 +214,46 @@
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
- return true;
+ return {};
}
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
- uint32_t* out_values, uint32_t* out_indices) {
- if (kDebugStyles) {
- ALOGI("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
- def_style_attr, def_style_resid, xml_parser);
- }
-
- AssetManager2* assetmanager = theme->GetAssetManager();
- ResTable_config config;
- Res_value value;
+base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser,
+ uint32_t def_style_attr,
+ uint32_t def_style_resid,
+ const uint32_t* attrs, size_t attrs_length,
+ uint32_t* out_values, uint32_t* out_indices) {
+ DEBUG_LOG("APPLY STYLE: theme=0x%p defStyleAttr=0x%x defStyleRes=0x%x xml=0x%p", theme,
+ def_style_attr, def_style_resid, xml_parser);
int indices_idx = 0;
+ const AssetManager2* assetmanager = theme->GetAssetManager();
// Load default style from attribute, if specified...
- uint32_t def_style_flags = 0u;
- if (def_style_attr != 0) {
- Res_value value;
- if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
- if (value.dataType == Res_value::TYPE_REFERENCE) {
- def_style_resid = value.data;
- }
- }
+ uint32_t def_style_theme_flags = 0U;
+ const auto default_style_bag = GetStyleBag(theme, def_style_attr, def_style_resid,
+ &def_style_theme_flags);
+ if (IsIOError(default_style_bag)) {
+ return base::unexpected(GetIOError(default_style_bag.error()));
}
// Retrieve the style resource ID associated with the current XML tag's style attribute.
- uint32_t style_resid = 0u;
- uint32_t style_flags = 0u;
- if (xml_parser != nullptr) {
- ssize_t idx = xml_parser->indexOfStyle();
- if (idx >= 0 && xml_parser->getAttributeValue(idx, &value) >= 0) {
- if (value.dataType == value.TYPE_ATTRIBUTE) {
- // Resolve the attribute with out theme.
- if (theme->GetAttribute(value.data, &value, &style_flags) == kInvalidCookie) {
- value.dataType = Res_value::TYPE_NULL;
- }
- }
-
- if (value.dataType == value.TYPE_REFERENCE) {
- style_resid = value.data;
- }
- }
+ uint32_t xml_style_theme_flags = 0U;
+ const auto xml_style_bag = GetXmlStyleBag(theme, xml_parser, &def_style_theme_flags);
+ if (IsIOError(xml_style_bag)) {
+ return base::unexpected(GetIOError(xml_style_bag.error()));
}
- // Retrieve the default style bag, if requested.
- const ResolvedBag* default_style_bag = nullptr;
- if (def_style_resid != 0) {
- default_style_bag = assetmanager->GetBag(def_style_resid);
- if (default_style_bag != nullptr) {
- def_style_flags |= default_style_bag->type_spec_flags;
- }
- }
-
- BagAttributeFinder def_style_attr_finder(default_style_bag);
-
- // Retrieve the style class bag, if requested.
- const ResolvedBag* xml_style_bag = nullptr;
- if (style_resid != 0) {
- xml_style_bag = assetmanager->GetBag(style_resid);
- if (xml_style_bag != nullptr) {
- style_flags |= xml_style_bag->type_spec_flags;
- }
- }
-
- BagAttributeFinder xml_style_attr_finder(xml_style_bag);
-
- // Retrieve the XML attributes, if requested.
+ BagAttributeFinder def_style_attr_finder(default_style_bag.value_or(nullptr));
+ BagAttributeFinder xml_style_attr_finder(xml_style_bag.value_or(nullptr));
XmlAttributeFinder xml_attr_finder(xml_parser);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
+ DEBUG_LOG("RETRIEVING ATTR 0x%08x...", cur_ident);
- if (kDebugStyles) {
- ALOGI("RETRIEVING ATTR 0x%08x...", cur_ident);
- }
-
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ AssetManager2::SelectedValue value{};
uint32_t value_source_resid = 0;
// Try to find a value for this attribute... we prioritize values
@@ -296,178 +264,152 @@
const size_t xml_attr_idx = xml_attr_finder.Find(cur_ident);
if (xml_attr_idx != xml_attr_finder.end()) {
// We found the attribute we were looking for.
- xml_parser->getAttributeValue(xml_attr_idx, &value);
- if (kDebugStyles) {
- ALOGI("-> From XML: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ Res_value attribute_value{};
+ xml_parser->getAttributeValue(xml_attr_idx, &attribute_value);
+ value.type = attribute_value.dataType;
+ value.data = attribute_value.data;
value_source_resid = xml_parser->getSourceResourceId();
+ DEBUG_LOG("-> From XML: type=0x%x, data=0x%08x", value.type, value.data);
}
- if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the style class values looking for the requested attribute.
const ResolvedBag::Entry* entry = xml_style_attr_finder.Find(cur_ident);
if (entry != xml_style_attr_finder.end()) {
- // We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = style_flags;
- value = entry->value;
+ value = AssetManager2::SelectedValue(*xml_style_bag, *entry);
+ value.flags |= xml_style_theme_flags;
value_source_resid = entry->style;
- if (kDebugStyles) {
- ALOGI("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
- entry->style);
- }
+ DEBUG_LOG("-> From style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
+ value_source_resid);
}
}
- if (value.dataType == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
+ if (value.type == Res_value::TYPE_NULL && value.data != Res_value::DATA_NULL_EMPTY) {
// Walk through the default style values looking for the requested attribute.
const ResolvedBag::Entry* entry = def_style_attr_finder.Find(cur_ident);
if (entry != def_style_attr_finder.end()) {
- // We found the attribute we were looking for.
- cookie = entry->cookie;
- type_set_flags = def_style_flags;
- value = entry->value;
- if (kDebugStyles) {
- ALOGI("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.dataType, value.data,
- entry->style);
- }
+ value = AssetManager2::SelectedValue(*default_style_bag, *entry);
+ value.flags |= def_style_theme_flags;
value_source_resid = entry->style;
+ DEBUG_LOG("-> From def style: type=0x%x, data=0x%08x, style=0x%08x", value.type, value.data,
+ entry->style);
}
}
- uint32_t resid = 0u;
- if (value.dataType != Res_value::TYPE_NULL) {
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- theme->ResolveAttributeReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ auto result = theme->ResolveAttributeReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
-
- if (kDebugStyles) {
- ALOGI("-> Resolved attr: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
+ DEBUG_LOG("-> Resolved attr: type=0x%x, data=0x%08x", value.type, value.data);
} else if (value.data != Res_value::DATA_NULL_EMPTY) {
// If we still don't have a value for this attribute, try to find it in the theme!
- ApkAssetsCookie new_cookie = theme->GetAttribute(cur_ident, &value, &type_set_flags);
- // TODO: set value_source_resid for the style in the theme that was used.
- if (new_cookie != kInvalidCookie) {
- if (kDebugStyles) {
- ALOGI("-> From theme: type=0x%x, data=0x%08x", value.dataType, value.data);
- }
- new_cookie =
- assetmanager->ResolveReference(new_cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
- }
+ if (auto attr_value = theme->GetAttribute(cur_ident)) {
+ value = *attr_value;
+ DEBUG_LOG("-> From theme: type=0x%x, data=0x%08x", value.type, value.data);
- if (kDebugStyles) {
- ALOGI("-> Resolved theme: type=0x%x, data=0x%08x", value.dataType, value.data);
+ auto result = assetmanager->ResolveReference(value, true /* cache_value */);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
+ DEBUG_LOG("-> Resolved theme: type=0x%x, data=0x%08x", value.type, value.data);
+ // TODO: set value_source_resid for the style in the theme that was used.
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- if (kDebugStyles) {
- ALOGI("-> Setting to @null!");
- }
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
+ DEBUG_LOG("-> Setting to @null!");
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
- if (kDebugStyles) {
- ALOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.dataType, value.data);
- }
+ DEBUG_LOG("Attribute 0x%08x: type=0x%x, data=0x%08x", cur_ident, value.type, value.data);
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
out_values[STYLE_SOURCE_RESOURCE_ID] = value_source_resid;
- if (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
- indices_idx++;
-
+ if (value.type != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY) {
// out_indices must NOT be nullptr.
- out_indices[indices_idx] = ii;
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
}
// out_indices must NOT be nullptr.
out_indices[0] = indices_idx;
+ return {};
}
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices) {
- ResTable_config config;
- Res_value value;
-
+base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager,
+ ResXMLParser* xml_parser,
+ uint32_t* attrs,
+ size_t attrs_length,
+ uint32_t* out_values,
+ uint32_t* out_indices) {
int indices_idx = 0;
// Retrieve the XML attributes, if requested.
- const size_t xml_attr_count = xml_parser->getAttributeCount();
size_t ix = 0;
+ const size_t xml_attr_count = xml_parser->getAttributeCount();
uint32_t cur_xml_attr = xml_parser->getAttributeNameResID(ix);
// Now iterate through all of the attributes that the client has requested,
// filling in each with whatever data we can find.
for (size_t ii = 0; ii < attrs_length; ii++) {
const uint32_t cur_ident = attrs[ii];
- ApkAssetsCookie cookie = kInvalidCookie;
- uint32_t type_set_flags = 0u;
-
- value.dataType = Res_value::TYPE_NULL;
- value.data = Res_value::DATA_NULL_UNDEFINED;
- config.density = 0;
+ AssetManager2::SelectedValue value{};
// Try to find a value for this attribute...
// Skip through XML attributes until the end or the next possible match.
while (ix < xml_attr_count && cur_ident > cur_xml_attr) {
- ix++;
- cur_xml_attr = xml_parser->getAttributeNameResID(ix);
- }
- // Retrieve the current XML attribute if it matches, and step to next.
- if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
- xml_parser->getAttributeValue(ix, &value);
- ix++;
- cur_xml_attr = xml_parser->getAttributeNameResID(ix);
+ cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
}
- uint32_t resid = 0u;
- if (value.dataType != Res_value::TYPE_NULL) {
+ // Retrieve the current XML attribute if it matches, and step to next.
+ if (ix < xml_attr_count && cur_ident == cur_xml_attr) {
+ Res_value attribute_value{};
+ xml_parser->getAttributeValue(ix, &attribute_value);
+ value.type = attribute_value.dataType;
+ value.data = attribute_value.data;
+ cur_xml_attr = xml_parser->getAttributeNameResID(++ix);
+ }
+
+ if (value.type != Res_value::TYPE_NULL) {
// Take care of resolving the found resource to its final value.
- ApkAssetsCookie new_cookie =
- assetmanager->ResolveReference(cookie, &value, &config, &type_set_flags, &resid);
- if (new_cookie != kInvalidCookie) {
- cookie = new_cookie;
+ auto result = assetmanager->ResolveReference(value);
+ if (UNLIKELY(IsIOError(result))) {
+ return base::unexpected(GetIOError(result.error()));
}
}
// Deal with the special @null value -- it turns back to TYPE_NULL.
- if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
- value.dataType = Res_value::TYPE_NULL;
+ if (value.type == Res_value::TYPE_REFERENCE && value.data == 0U) {
+ value.type = Res_value::TYPE_NULL;
value.data = Res_value::DATA_NULL_UNDEFINED;
- cookie = kInvalidCookie;
+ value.cookie = kInvalidCookie;
}
// Write the final value back to Java.
- out_values[STYLE_TYPE] = value.dataType;
+ out_values[STYLE_TYPE] = value.type;
out_values[STYLE_DATA] = value.data;
- out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(cookie);
- out_values[STYLE_RESOURCE_ID] = resid;
- out_values[STYLE_CHANGING_CONFIGURATIONS] = type_set_flags;
- out_values[STYLE_DENSITY] = config.density;
+ out_values[STYLE_ASSET_COOKIE] = ApkAssetsCookieToJavaCookie(value.cookie);
+ out_values[STYLE_RESOURCE_ID] = value.resid;
+ out_values[STYLE_CHANGING_CONFIGURATIONS] = value.flags;
+ out_values[STYLE_DENSITY] = value.config.density;
if (out_indices != nullptr &&
- (value.dataType != Res_value::TYPE_NULL || value.data == Res_value::DATA_NULL_EMPTY)) {
- indices_idx++;
- out_indices[indices_idx] = ii;
+ (value.type != Res_value::TYPE_NULL ||
+ value.data == Res_value::DATA_NULL_EMPTY)) {
+ out_indices[++indices_idx] = ii;
}
out_values += STYLE_NUM_ENTRIES;
@@ -476,7 +418,7 @@
if (out_indices != nullptr) {
out_indices[0] = indices_idx;
}
- return true;
+ return {};
}
} // namespace android
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
index 8fc3219..25c8aa6 100644
--- a/libs/androidfw/ChunkIterator.cpp
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -15,6 +15,7 @@
*/
#include "androidfw/Chunk.h"
+#include "androidfw/Util.h"
#include "android-base/logging.h"
@@ -23,11 +24,11 @@
Chunk ChunkIterator::Next() {
CHECK(len_ != 0) << "called Next() after last chunk";
- const ResChunk_header* this_chunk = next_chunk_;
+ const incfs::map_ptr<ResChunk_header> this_chunk = next_chunk_;
+ CHECK((bool) this_chunk) << "Next() called without verifying next chunk";
// We've already checked the values of this_chunk, so safely increment.
- next_chunk_ = reinterpret_cast<const ResChunk_header*>(
- reinterpret_cast<const uint8_t*>(this_chunk) + dtohl(this_chunk->size));
+ next_chunk_ = this_chunk.offset(dtohl(this_chunk->size)).convert<ResChunk_header>();
len_ -= dtohl(this_chunk->size);
if (len_ != 0) {
@@ -36,7 +37,7 @@
VerifyNextChunk();
}
}
- return Chunk(this_chunk);
+ return Chunk(this_chunk.verified());
}
// TODO(b/111401637) remove this and have full resource file verification
@@ -47,6 +48,13 @@
last_error_was_fatal_ = false;
return false;
}
+
+ if (!next_chunk_) {
+ last_error_ = "failed to read chunk from data";
+ last_error_was_fatal_ = false;
+ return false;
+ }
+
const size_t size = dtohl(next_chunk_->size);
if (size > len_) {
last_error_ = "chunk size is bigger than given data";
@@ -58,12 +66,10 @@
// Returns false if there was an error.
bool ChunkIterator::VerifyNextChunk() {
- const uintptr_t header_start = reinterpret_cast<uintptr_t>(next_chunk_);
-
// This data must be 4-byte aligned, since we directly
// access 32-bit words, which must be aligned on
// certain architectures.
- if (header_start & 0x03) {
+ if (!util::IsFourByteAligned(next_chunk_)) {
last_error_ = "header not aligned on 4-byte boundary";
return false;
}
@@ -73,6 +79,11 @@
return false;
}
+ if (!next_chunk_) {
+ last_error_ = "failed to read chunk from data";
+ return false;
+ }
+
const size_t header_size = dtohs(next_chunk_->headerSize);
const size_t size = dtohl(next_chunk_->size);
if (header_size < sizeof(ResChunk_header)) {
@@ -90,7 +101,7 @@
return false;
}
- if ((size | header_size) & 0x03) {
+ if ((size | header_size) & 0x03U) {
last_error_ = "header sizes are not aligned on 4-byte boundary";
return false;
}
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index 4e03ce5..a613095 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -52,22 +52,22 @@
uninit();
}
-const char16_t* OverlayStringPool::stringAt(size_t idx, size_t* outLen) const {
+base::expected<StringPiece16, NullOrIOError> OverlayStringPool::stringAt(size_t idx) const {
const size_t offset = dtohl(data_header_->string_pool_index_offset);
if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
- return idmap_string_pool_->stringAt(idx - offset, outLen);
+ return idmap_string_pool_->stringAt(idx - offset);
}
- return ResStringPool::stringAt(idx, outLen);
+ return ResStringPool::stringAt(idx);
}
-const char* OverlayStringPool::string8At(size_t idx, size_t* outLen) const {
+base::expected<StringPiece, NullOrIOError> OverlayStringPool::string8At(size_t idx) const {
const size_t offset = dtohl(data_header_->string_pool_index_offset);
if (idmap_string_pool_ != nullptr && idx >= ResStringPool::size() && idx >= offset) {
- return idmap_string_pool_->string8At(idx - offset, outLen);
+ return idmap_string_pool_->string8At(idx - offset);
}
- return ResStringPool::string8At(idx, outLen);
+ return ResStringPool::string8At(idx);
}
size_t OverlayStringPool::size() const {
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 70bb441..2fc3b05 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -38,7 +38,7 @@
#include "androidfw/ResourceUtils.h"
#include "androidfw/Util.h"
-using ::android::base::StringPrintf;
+using android::base::StringPrintf;
namespace android {
@@ -51,17 +51,17 @@
// the Type structs.
class TypeSpecPtrBuilder {
public:
- explicit TypeSpecPtrBuilder(const ResTable_typeSpec* header)
+ explicit TypeSpecPtrBuilder(incfs::verified_map_ptr<ResTable_typeSpec> header)
: header_(header) {
}
- void AddType(const ResTable_type* type) {
+ void AddType(incfs::verified_map_ptr<ResTable_type> type) {
types_.push_back(type);
}
TypeSpecPtr Build() {
// Check for overflow.
- using ElementType = const ResTable_type*;
+ using ElementType = incfs::verified_map_ptr<ResTable_type>;
if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(ElementType) <
types_.size()) {
return {};
@@ -77,8 +77,8 @@
private:
DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
- const ResTable_typeSpec* header_;
- std::vector<const ResTable_type*> types_;
+ incfs::verified_map_ptr<ResTable_typeSpec> header_;
+ std::vector<incfs::verified_map_ptr<ResTable_type>> types_;
};
} // namespace
@@ -88,7 +88,7 @@
// Precondition: The header passed in has already been verified, so reading any fields and trusting
// the ResChunk_header is safe.
-static bool VerifyResTableType(const ResTable_type* header) {
+static bool VerifyResTableType(incfs::map_ptr<ResTable_type> header) {
if (header->id == 0) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE has invalid ID 0.";
return false;
@@ -115,89 +115,99 @@
return false;
}
- if (entries_offset & 0x03) {
+ if (entries_offset & 0x03U) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE entries start at unaligned address.";
return false;
}
return true;
}
-static bool VerifyResTableEntry(const ResTable_type* type, uint32_t entry_offset) {
+static base::expected<std::monostate, NullOrIOError> VerifyResTableEntry(
+ incfs::verified_map_ptr<ResTable_type> type, uint32_t entry_offset) {
// Check that the offset is aligned.
- if (entry_offset & 0x03) {
+ if (UNLIKELY(entry_offset & 0x03U)) {
LOG(ERROR) << "Entry at offset " << entry_offset << " is not 4-byte aligned.";
- return false;
+ return base::unexpected(std::nullopt);
}
// Check that the offset doesn't overflow.
- if (entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart)) {
+ if (UNLIKELY(entry_offset > std::numeric_limits<uint32_t>::max() - dtohl(type->entriesStart))) {
// Overflow in offset.
LOG(ERROR) << "Entry at offset " << entry_offset << " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
const size_t chunk_size = dtohl(type->header.size);
entry_offset += dtohl(type->entriesStart);
- if (entry_offset > chunk_size - sizeof(ResTable_entry)) {
+ if (UNLIKELY(entry_offset > chunk_size - sizeof(ResTable_entry))) {
LOG(ERROR) << "Entry at offset " << entry_offset
<< " is too large. No room for ResTable_entry.";
- return false;
+ return base::unexpected(std::nullopt);
}
- const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(type) + entry_offset);
+ auto entry = type.offset(entry_offset).convert<ResTable_entry>();
+ if (UNLIKELY(!entry)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
const size_t entry_size = dtohs(entry->size);
- if (entry_size < sizeof(*entry)) {
+ if (UNLIKELY(entry_size < sizeof(entry.value()))) {
LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too small.";
- return false;
+ return base::unexpected(std::nullopt);
}
- if (entry_size > chunk_size || entry_offset > chunk_size - entry_size) {
+ if (UNLIKELY(entry_size > chunk_size || entry_offset > chunk_size - entry_size)) {
LOG(ERROR) << "ResTable_entry size " << entry_size << " at offset " << entry_offset
<< " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
if (entry_size < sizeof(ResTable_map_entry)) {
// There needs to be room for one Res_value struct.
- if (entry_offset + entry_size > chunk_size - sizeof(Res_value)) {
+ if (UNLIKELY(entry_offset + entry_size > chunk_size - sizeof(Res_value))) {
LOG(ERROR) << "No room for Res_value after ResTable_entry at offset " << entry_offset
<< " for type " << (int)type->id << ".";
- return false;
+ return base::unexpected(std::nullopt);
}
- const Res_value* value =
- reinterpret_cast<const Res_value*>(reinterpret_cast<const uint8_t*>(entry) + entry_size);
+ auto value = entry.offset(entry_size).convert<Res_value>();
+ if (UNLIKELY(!value)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
const size_t value_size = dtohs(value->size);
- if (value_size < sizeof(Res_value)) {
+ if (UNLIKELY(value_size < sizeof(Res_value))) {
LOG(ERROR) << "Res_value at offset " << entry_offset << " is too small.";
- return false;
+ return base::unexpected(std::nullopt);
}
- if (value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size) {
+ if (UNLIKELY(value_size > chunk_size || entry_offset + entry_size > chunk_size - value_size)) {
LOG(ERROR) << "Res_value size " << value_size << " at offset " << entry_offset
<< " is too large.";
- return false;
+ return base::unexpected(std::nullopt);
}
} else {
- const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
+ auto map = entry.convert<ResTable_map_entry>();
+ if (UNLIKELY(!map)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
const size_t map_entry_count = dtohl(map->count);
size_t map_entries_start = entry_offset + entry_size;
- if (map_entries_start & 0x03) {
+ if (UNLIKELY(map_entries_start & 0x03U)) {
LOG(ERROR) << "Map entries at offset " << entry_offset << " start at unaligned offset.";
- return false;
+ return base::unexpected(std::nullopt);
}
// Each entry is sizeof(ResTable_map) big.
- if (map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map))) {
+ if (UNLIKELY(map_entry_count > ((chunk_size - map_entries_start) / sizeof(ResTable_map)))) {
LOG(ERROR) << "Too many map entries in ResTable_map_entry at offset " << entry_offset << ".";
- return false;
+ return base::unexpected(std::nullopt);
}
}
- return true;
+ return {};
}
LoadedPackage::iterator::iterator(const LoadedPackage* lp, size_t ti, size_t ei)
@@ -233,99 +243,125 @@
entryIndex_);
}
-const ResTable_entry* LoadedPackage::GetEntry(const ResTable_type* type_chunk,
- uint16_t entry_index) {
- uint32_t entry_offset = GetEntryOffset(type_chunk, entry_index);
- if (entry_offset == ResTable_type::NO_ENTRY) {
- return nullptr;
+base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> LoadedPackage::GetEntry(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index) {
+ base::expected<uint32_t, NullOrIOError> entry_offset = GetEntryOffset(type_chunk, entry_index);
+ if (UNLIKELY(!entry_offset.has_value())) {
+ return base::unexpected(entry_offset.error());
}
- return GetEntryFromOffset(type_chunk, entry_offset);
+ return GetEntryFromOffset(type_chunk, entry_offset.value());
}
-uint32_t LoadedPackage::GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index) {
+base::expected<uint32_t, NullOrIOError> LoadedPackage::GetEntryOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index) {
// The configuration matches and is better than the previous selection.
// Find the entry value if it exists for this configuration.
const size_t entry_count = dtohl(type_chunk->entryCount);
const size_t offsets_offset = dtohs(type_chunk->header.headerSize);
// Check if there is the desired entry in this type.
-
if (type_chunk->flags & ResTable_type::FLAG_SPARSE) {
// This is encoded as a sparse map, so perform a binary search.
- const ResTable_sparseTypeEntry* sparse_indices =
- reinterpret_cast<const ResTable_sparseTypeEntry*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- const ResTable_sparseTypeEntry* sparse_indices_end = sparse_indices + entry_count;
- const ResTable_sparseTypeEntry* result =
- std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
- [](const ResTable_sparseTypeEntry& entry, uint16_t entry_idx) {
- return dtohs(entry.idx) < entry_idx;
- });
+ bool error = false;
+ auto sparse_indices = type_chunk.offset(offsets_offset)
+ .convert<ResTable_sparseTypeEntry>().iterator();
+ auto sparse_indices_end = sparse_indices + entry_count;
+ auto result = std::lower_bound(sparse_indices, sparse_indices_end, entry_index,
+ [&error](const incfs::map_ptr<ResTable_sparseTypeEntry>& entry,
+ uint16_t entry_idx) {
+ if (UNLIKELY(!entry)) {
+ return error = true;
+ }
+ return dtohs(entry->idx) < entry_idx;
+ });
- if (result == sparse_indices_end || dtohs(result->idx) != entry_index) {
+ if (result == sparse_indices_end) {
// No entry found.
- return ResTable_type::NO_ENTRY;
+ return base::unexpected(std::nullopt);
+ }
+
+ const incfs::verified_map_ptr<ResTable_sparseTypeEntry> entry = (*result).verified();
+ if (dtohs(entry->idx) != entry_index) {
+ if (error) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return base::unexpected(std::nullopt);
}
// Extract the offset from the entry. Each offset must be a multiple of 4 so we store it as
// the real offset divided by 4.
- return uint32_t{dtohs(result->offset)} * 4u;
+ return uint32_t{dtohs(entry->offset)} * 4u;
}
// This type is encoded as a dense array.
if (entry_index >= entry_count) {
// This entry cannot be here.
- return ResTable_type::NO_ENTRY;
+ return base::unexpected(std::nullopt);
}
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type_chunk) + offsets_offset);
- return dtohl(entry_offsets[entry_index]);
-}
-
-const ResTable_entry* LoadedPackage::GetEntryFromOffset(const ResTable_type* type_chunk,
- uint32_t offset) {
- if (UNLIKELY(!VerifyResTableEntry(type_chunk, offset))) {
- return nullptr;
+ const auto entry_offset_ptr = type_chunk.offset(offsets_offset).convert<uint32_t>() + entry_index;
+ if (UNLIKELY(!entry_offset_ptr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- return reinterpret_cast<const ResTable_entry*>(reinterpret_cast<const uint8_t*>(type_chunk) +
- offset + dtohl(type_chunk->entriesStart));
+
+ const uint32_t value = dtohl(entry_offset_ptr.value());
+ if (value == ResTable_type::NO_ENTRY) {
+ return base::unexpected(std::nullopt);
+ }
+
+ return value;
}
-void LoadedPackage::CollectConfigurations(bool exclude_mipmap,
- std::set<ResTable_config>* out_configs) const {
- const static std::u16string kMipMap = u"mipmap";
+base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> LoadedPackage::GetEntryFromOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset) {
+ auto valid = VerifyResTableEntry(type_chunk, offset);
+ if (UNLIKELY(!valid.has_value())) {
+ return base::unexpected(valid.error());
+ }
+ return type_chunk.offset(offset + dtohl(type_chunk->entriesStart)).convert<ResTable_entry>();
+}
+
+base::expected<std::monostate, IOError> LoadedPackage::CollectConfigurations(
+ bool exclude_mipmap, std::set<ResTable_config>* out_configs) const {
const size_t type_count = type_specs_.size();
for (size_t i = 0; i < type_count; i++) {
const TypeSpecPtr& type_spec = type_specs_[i];
- if (type_spec != nullptr) {
- if (exclude_mipmap) {
- const int type_idx = type_spec->type_spec->id - 1;
- size_t type_name_len;
- const char16_t* type_name16 = type_string_pool_.stringAt(type_idx, &type_name_len);
- if (type_name16 != nullptr) {
- if (kMipMap.compare(0, std::u16string::npos, type_name16, type_name_len) == 0) {
- // This is a mipmap type, skip collection.
- continue;
- }
- }
- const char* type_name = type_string_pool_.string8At(type_idx, &type_name_len);
- if (type_name != nullptr) {
- if (strncmp(type_name, "mipmap", type_name_len) == 0) {
- // This is a mipmap type, skip collection.
- continue;
- }
+ if (type_spec == nullptr) {
+ continue;
+ }
+ if (exclude_mipmap) {
+ const int type_idx = type_spec->type_spec->id - 1;
+ const auto type_name16 = type_string_pool_.stringAt(type_idx);
+ if (UNLIKELY(IsIOError(type_name16))) {
+ return base::unexpected(GetIOError(type_name16.error()));
+ }
+ if (type_name16.has_value()) {
+ if (strncmp16(type_name16->data(), u"mipmap", type_name16->size()) == 0) {
+ // This is a mipmap type, skip collection.
+ continue;
}
}
- const auto iter_end = type_spec->types + type_spec->type_count;
- for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- ResTable_config config;
- config.copyFromDtoH((*iter)->config);
- out_configs->insert(config);
+ const auto type_name = type_string_pool_.string8At(type_idx);
+ if (UNLIKELY(IsIOError(type_name))) {
+ return base::unexpected(GetIOError(type_name.error()));
+ }
+ if (type_name.has_value()) {
+ if (strncmp(type_name->data(), "mipmap", type_name->size()) == 0) {
+ // This is a mipmap type, skip collection.
+ continue;
+ }
}
}
+
+ const auto iter_end = type_spec->types + type_spec->type_count;
+ for (auto iter = type_spec->types; iter != iter_end; ++iter) {
+ ResTable_config config;
+ config.copyFromDtoH((*iter)->config);
+ out_configs->insert(config);
+ }
}
+ return {};
}
void LoadedPackage::CollectLocales(bool canonicalize, std::set<std::string>* out_locales) const {
@@ -348,43 +384,53 @@
}
}
-uint32_t LoadedPackage::FindEntryByName(const std::u16string& type_name,
- const std::u16string& entry_name) const {
- ssize_t type_idx = type_string_pool_.indexOfString(type_name.data(), type_name.size());
- if (type_idx < 0) {
- return 0u;
+base::expected<uint32_t, NullOrIOError> LoadedPackage::FindEntryByName(
+ const std::u16string& type_name, const std::u16string& entry_name) const {
+ const base::expected<size_t, NullOrIOError> type_idx = type_string_pool_.indexOfString(
+ type_name.data(), type_name.size());
+ if (!type_idx.has_value()) {
+ return base::unexpected(type_idx.error());
}
- ssize_t key_idx = key_string_pool_.indexOfString(entry_name.data(), entry_name.size());
- if (key_idx < 0) {
- return 0u;
+ const base::expected<size_t, NullOrIOError> key_idx = key_string_pool_.indexOfString(
+ entry_name.data(), entry_name.size());
+ if (!key_idx.has_value()) {
+ return base::unexpected(key_idx.error());
}
- const TypeSpec* type_spec = type_specs_[type_idx].get();
+ const TypeSpec* type_spec = type_specs_[*type_idx].get();
if (type_spec == nullptr) {
- return 0u;
+ return base::unexpected(std::nullopt);
}
const auto iter_end = type_spec->types + type_spec->type_count;
for (auto iter = type_spec->types; iter != iter_end; ++iter) {
- const ResTable_type* type = *iter;
+ const incfs::verified_map_ptr<ResTable_type>& type = *iter;
+
size_t entry_count = dtohl(type->entryCount);
for (size_t entry_idx = 0; entry_idx < entry_count; entry_idx++) {
- const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
- reinterpret_cast<const uint8_t*>(type) + dtohs(type->header.headerSize));
- const uint32_t offset = dtohl(entry_offsets[entry_idx]);
+ auto entry_offset_ptr = type.offset(dtohs(type->header.headerSize)).convert<uint32_t>() +
+ entry_idx;
+ if (!entry_offset_ptr) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ auto offset = dtohl(entry_offset_ptr.value());
if (offset != ResTable_type::NO_ENTRY) {
- const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
- reinterpret_cast<const uint8_t*>(type) + dtohl(type->entriesStart) + offset);
- if (dtohl(entry->key.index) == static_cast<uint32_t>(key_idx)) {
+ auto entry = type.offset(dtohl(type->entriesStart) + offset).convert<ResTable_entry>();
+ if (!entry) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ if (dtohl(entry->key.index) == static_cast<uint32_t>(*key_idx)) {
// The package ID will be overridden by the caller (due to runtime assignment of package
// IDs for shared libraries).
- return make_resid(0x00, type_idx + type_id_offset_ + 1, entry_idx);
+ return make_resid(0x00, *type_idx + type_id_offset_ + 1, entry_idx);
}
}
}
}
- return 0u;
+ return base::unexpected(std::nullopt);
}
const LoadedPackage* LoadedArsc::GetPackageById(uint8_t package_id) const {
@@ -405,8 +451,8 @@
// was added.
constexpr size_t kMinPackageSize =
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
- const ResTable_package* header = chunk.header<ResTable_package, kMinPackageSize>();
- if (header == nullptr) {
+ const incfs::map_ptr<ResTable_package> header = chunk.header<ResTable_package, kMinPackageSize>();
+ if (!header) {
LOG(ERROR) << "RES_TABLE_PACKAGE_TYPE too small.";
return {};
}
@@ -453,10 +499,13 @@
const Chunk child_chunk = iter.Next();
switch (child_chunk.type()) {
case RES_STRING_POOL_TYPE: {
- const uintptr_t pool_address =
- reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>());
- const uintptr_t header_address = reinterpret_cast<uintptr_t>(header);
- if (pool_address == header_address + dtohl(header->typeStrings)) {
+ const auto pool_address = child_chunk.header<ResChunk_header>();
+ if (!pool_address) {
+ LOG(ERROR) << "RES_STRING_POOL_TYPE is incomplete due to incremental installation.";
+ return {};
+ }
+
+ if (pool_address == header.offset(dtohl(header->typeStrings)).convert<ResChunk_header>()) {
// This string pool is the type string pool.
status_t err = loaded_package->type_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
@@ -464,7 +513,8 @@
LOG(ERROR) << "RES_STRING_POOL_TYPE for types corrupt.";
return {};
}
- } else if (pool_address == header_address + dtohl(header->keyStrings)) {
+ } else if (pool_address == header.offset(dtohl(header->keyStrings))
+ .convert<ResChunk_header>()) {
// This string pool is the key string pool.
status_t err = loaded_package->key_string_pool_.setTo(
child_chunk.header<ResStringPool_header>(), child_chunk.size());
@@ -478,8 +528,8 @@
} break;
case RES_TABLE_TYPE_SPEC_TYPE: {
- const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
- if (type_spec == nullptr) {
+ const auto type_spec = child_chunk.header<ResTable_typeSpec>();
+ if (!type_spec) {
LOG(ERROR) << "RES_TABLE_TYPE_SPEC_TYPE too small.";
return {};
}
@@ -514,7 +564,7 @@
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type_spec->id - 1];
if (builder_ptr == nullptr) {
- builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec);
+ builder_ptr = util::make_unique<TypeSpecPtrBuilder>(type_spec.verified());
loaded_package->resource_ids_.set(type_spec->id, entry_count);
} else {
LOG(WARNING) << StringPrintf("RES_TABLE_TYPE_SPEC_TYPE already defined for ID %02x",
@@ -523,8 +573,8 @@
} break;
case RES_TABLE_TYPE_TYPE: {
- const ResTable_type* type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
- if (type == nullptr) {
+ const auto type = child_chunk.header<ResTable_type, kResTableTypeMinSize>();
+ if (!type) {
LOG(ERROR) << "RES_TABLE_TYPE_TYPE too small.";
return {};
}
@@ -536,7 +586,7 @@
// Type chunks must be preceded by their TypeSpec chunks.
std::unique_ptr<TypeSpecPtrBuilder>& builder_ptr = type_builder_map[type->id - 1];
if (builder_ptr != nullptr) {
- builder_ptr->AddType(type);
+ builder_ptr->AddType(type.verified());
} else {
LOG(ERROR) << StringPrintf(
"RES_TABLE_TYPE_TYPE with ID %02x found without preceding RES_TABLE_TYPE_SPEC_TYPE.",
@@ -546,8 +596,8 @@
} break;
case RES_TABLE_LIBRARY_TYPE: {
- const ResTable_lib_header* lib = child_chunk.header<ResTable_lib_header>();
- if (lib == nullptr) {
+ const auto lib = child_chunk.header<ResTable_lib_header>();
+ if (!lib) {
LOG(ERROR) << "RES_TABLE_LIBRARY_TYPE too small.";
return {};
}
@@ -559,10 +609,13 @@
loaded_package->dynamic_package_map_.reserve(dtohl(lib->count));
- const ResTable_lib_entry* const entry_begin =
- reinterpret_cast<const ResTable_lib_entry*>(child_chunk.data_ptr());
- const ResTable_lib_entry* const entry_end = entry_begin + dtohl(lib->count);
+ const auto entry_begin = child_chunk.data_ptr().convert<ResTable_lib_entry>();
+ const auto entry_end = entry_begin + dtohl(lib->count);
for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
+ if (!entry_iter) {
+ return {};
+ }
+
std::string package_name;
util::ReadUtf16StringFromDevice(entry_iter->packageName,
arraysize(entry_iter->packageName), &package_name);
@@ -580,17 +633,16 @@
} break;
case RES_TABLE_OVERLAYABLE_TYPE: {
- const ResTable_overlayable_header* header =
- child_chunk.header<ResTable_overlayable_header>();
- if (header == nullptr) {
+ const auto overlayable = child_chunk.header<ResTable_overlayable_header>();
+ if (!overlayable) {
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_TYPE too small.";
return {};
}
std::string name;
- util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name);
+ util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
std::string actor;
- util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
+ util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);
if (loaded_package->overlayable_map_.find(name) !=
loaded_package->overlayable_map_.end()) {
@@ -606,9 +658,9 @@
switch (overlayable_child_chunk.type()) {
case RES_TABLE_OVERLAYABLE_POLICY_TYPE: {
- const ResTable_overlayable_policy_header* policy_header =
+ const auto policy_header =
overlayable_child_chunk.header<ResTable_overlayable_policy_header>();
- if (policy_header == nullptr) {
+ if (!policy_header) {
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
return {};
}
@@ -621,10 +673,12 @@
// Retrieve all the resource ids belonging to this policy chunk
std::unordered_set<uint32_t> ids;
- const auto ids_begin =
- reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr());
+ const auto ids_begin = overlayable_child_chunk.data_ptr().convert<ResTable_ref>();
const auto ids_end = ids_begin + dtohl(policy_header->entry_count);
for (auto id_iter = ids_begin; id_iter != ids_end; ++id_iter) {
+ if (!id_iter) {
+ return {};
+ }
ids.insert(dtohl(id_iter->ident));
}
@@ -633,7 +687,7 @@
overlayable_info.name = name;
overlayable_info.actor = actor;
overlayable_info.policy_flags = policy_header->policy_flags;
- loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids));
+ loaded_package->overlayable_infos_.emplace_back(overlayable_info, ids);
loaded_package->defines_overlayable_ = true;
break;
}
@@ -683,8 +737,8 @@
bool LoadedArsc::LoadTable(const Chunk& chunk, const LoadedIdmap* loaded_idmap,
package_property_t property_flags) {
- const ResTable_header* header = chunk.header<ResTable_header>();
- if (header == nullptr) {
+ incfs::map_ptr<ResTable_header> header = chunk.header<ResTable_header>();
+ if (!header) {
LOG(ERROR) << "RES_TABLE_TYPE too small.";
return false;
}
@@ -747,7 +801,8 @@
return true;
}
-std::unique_ptr<const LoadedArsc> LoadedArsc::Load(const StringPiece& data,
+std::unique_ptr<const LoadedArsc> LoadedArsc::Load(incfs::map_ptr<void> data,
+ const size_t length,
const LoadedIdmap* loaded_idmap,
const package_property_t property_flags) {
ATRACE_NAME("LoadedArsc::Load");
@@ -755,7 +810,7 @@
// Not using make_unique because the constructor is private.
std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
- ChunkIterator iter(data.data(), data.size());
+ ChunkIterator iter(data, length);
while (iter.HasNext()) {
const Chunk chunk = iter.Next();
switch (chunk.type()) {
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index dfb4009..4010e4e 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -104,22 +104,26 @@
*dst = 0;
}
-static status_t validate_chunk(const ResChunk_header* chunk,
+static status_t validate_chunk(const incfs::map_ptr<ResChunk_header>& chunk,
size_t minSize,
- const uint8_t* dataEnd,
+ const incfs::map_ptr<uint8_t> dataEnd,
const char* name)
{
+ if (!chunk) {
+ return BAD_TYPE;
+ }
+
const uint16_t headerSize = dtohs(chunk->headerSize);
const uint32_t size = dtohl(chunk->size);
if (headerSize >= minSize) {
if (headerSize <= size) {
if (((headerSize|size)&0x3) == 0) {
- if ((size_t)size <= (size_t)(dataEnd-((const uint8_t*)chunk))) {
+ if ((size_t)size <= (size_t)(dataEnd-chunk.convert<uint8_t>())) {
return NO_ERROR;
}
ALOGW("%s data size 0x%x extends beyond resource end %p.",
- name, size, (void*)(dataEnd-((const uint8_t*)chunk)));
+ name, size, (void*)(dataEnd-chunk.convert<uint8_t>()));
return BAD_TYPE;
}
ALOGW("%s size 0x%x or headerSize 0x%x is not on an integer boundary.",
@@ -450,7 +454,7 @@
mHeader = (const ResStringPool_header*) header;
}
-status_t ResStringPool::setTo(const void* data, size_t size, bool copyData)
+status_t ResStringPool::setTo(incfs::map_ptr<void> data, size_t size, bool copyData)
{
if (!data || !size) {
return (mError=BAD_TYPE);
@@ -467,8 +471,8 @@
// The data is at least as big as a ResChunk_header, so we can safely validate the other
// header fields.
// `data + size` is safe because the source of `size` comes from the kernel/filesystem.
- if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
- reinterpret_cast<const uint8_t*>(data) + size,
+ const auto chunk_header = data.convert<ResChunk_header>();
+ if (validate_chunk(chunk_header, sizeof(ResStringPool_header), data.convert<uint8_t>() + size,
"ResStringPool_header") != NO_ERROR) {
ALOGW("Bad string block: malformed block dimensions");
return (mError=BAD_TYPE);
@@ -481,16 +485,25 @@
if (mOwnedData == NULL) {
return (mError=NO_MEMORY);
}
- memcpy(mOwnedData, data, size);
+
+ if (!data.convert<uint8_t>().verify(size)) {
+ return (mError=NO_MEMORY);
+ }
+
+ memcpy(mOwnedData, data.unsafe_ptr(), size);
data = mOwnedData;
}
// The size has been checked, so it is safe to read the data in the ResStringPool_header
// data structure.
- mHeader = (const ResStringPool_header*)data;
+ const auto header = data.convert<ResStringPool_header>();
+ if (!header) {
+ return (mError=BAD_TYPE);
+ }
+ mHeader = header.verified();
if (notDeviceEndian) {
- ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader);
+ ResStringPool_header* h = const_cast<ResStringPool_header*>(mHeader.unsafe_ptr());
h->header.headerSize = dtohs(mHeader->header.headerSize);
h->header.type = dtohs(mHeader->header.type);
h->header.size = dtohl(mHeader->header.size);
@@ -508,8 +521,7 @@
return (mError=BAD_TYPE);
}
mSize = mHeader->header.size;
- mEntries = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->header.headerSize);
+ mEntries = data.offset(mHeader->header.headerSize).convert<uint32_t>();
if (mHeader->stringCount > 0) {
if ((mHeader->stringCount*sizeof(uint32_t) < mHeader->stringCount) // uint32 overflow?
@@ -536,9 +548,7 @@
return (mError=BAD_TYPE);
}
- mStrings = (const void*)
- (((const uint8_t*)data) + mHeader->stringsStart);
-
+ mStrings = data.offset(mHeader->stringsStart).convert<void>();
if (mHeader->styleCount == 0) {
mStringPoolSize = (mSize - mHeader->stringsStart) / charSize;
} else {
@@ -560,31 +570,37 @@
// check invariant: stringCount > 0 requires a string pool to exist
if (mStringPoolSize == 0) {
- ALOGW("Bad string block: stringCount is %d but pool size is 0\n", (int)mHeader->stringCount);
+ ALOGW("Bad string block: stringCount is %d but pool size is 0\n",
+ (int)mHeader->stringCount);
return (mError=BAD_TYPE);
}
if (notDeviceEndian) {
size_t i;
- uint32_t* e = const_cast<uint32_t*>(mEntries);
+ auto e = const_cast<uint32_t*>(mEntries.unsafe_ptr());
for (i=0; i<mHeader->stringCount; i++) {
- e[i] = dtohl(mEntries[i]);
+ e[i] = dtohl(e[i]);
}
if (!(mHeader->flags&ResStringPool_header::UTF8_FLAG)) {
- const uint16_t* strings = (const uint16_t*)mStrings;
- uint16_t* s = const_cast<uint16_t*>(strings);
+ uint16_t* s = const_cast<uint16_t*>(mStrings.convert<uint16_t>().unsafe_ptr());
for (i=0; i<mStringPoolSize; i++) {
- s[i] = dtohs(strings[i]);
+ s[i] = dtohs(s[i]);
}
}
}
- if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
- ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
- (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
- ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
- ALOGW("Bad string block: last string is not 0-terminated\n");
- return (mError=BAD_TYPE);
+ if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
+ auto end = mStrings.convert<uint8_t>() + (mStringPoolSize-1);
+ if (!end || end.value() != 0) {
+ ALOGW("Bad string block: last string is not 0-terminated\n");
+ return (mError=BAD_TYPE);
+ }
+ } else {
+ auto end = mStrings.convert<uint16_t>() + (mStringPoolSize-1);
+ if (!end || end.value() != 0) {
+ ALOGW("Bad string block: last string is not 0-terminated\n");
+ return (mError=BAD_TYPE);
+ }
}
} else {
mStrings = NULL;
@@ -599,14 +615,13 @@
return (mError=BAD_TYPE);
}
- if (((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader) > (int)size) {
+ if ((mEntryStyles.convert<uint8_t>() - mHeader.convert<uint8_t>()) > (int)size) {
ALOGW("Bad string block: entry of %d styles extends past data size %d\n",
- (int)((const uint8_t*)mEntryStyles-(const uint8_t*)mHeader),
+ (int)(mEntryStyles.convert<uint8_t>()-mHeader.convert<uint8_t>()),
(int)size);
return (mError=BAD_TYPE);
}
- mStyles = (const uint32_t*)
- (((const uint8_t*)data)+mHeader->stylesStart);
+ mStyles = data.offset(mHeader->stylesStart).convert<uint32_t>();
if (mHeader->stylesStart >= mHeader->header.size) {
ALOGW("Bad string block: style pool starts %d, after total size %d\n",
(int)mHeader->stylesStart, (int)mHeader->header.size);
@@ -617,13 +632,13 @@
if (notDeviceEndian) {
size_t i;
- uint32_t* e = const_cast<uint32_t*>(mEntryStyles);
+ uint32_t* e = const_cast<uint32_t*>(mEntryStyles.unsafe_ptr());
for (i=0; i<mHeader->styleCount; i++) {
- e[i] = dtohl(mEntryStyles[i]);
+ e[i] = dtohl(e[i]);
}
- uint32_t* s = const_cast<uint32_t*>(mStyles);
+ uint32_t* s = const_cast<uint32_t*>(mStyles.unsafe_ptr());
for (i=0; i<mStylePoolSize; i++) {
- s[i] = dtohl(mStyles[i]);
+ s[i] = dtohl(s[i]);
}
}
@@ -631,8 +646,9 @@
{ htodl(ResStringPool_span::END) },
htodl(ResStringPool_span::END), htodl(ResStringPool_span::END)
};
- if (memcmp(&mStyles[mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t))],
- &endSpan, sizeof(endSpan)) != 0) {
+
+ auto stylesEnd = mStyles + (mStylePoolSize-(sizeof(endSpan)/sizeof(uint32_t)));
+ if (!stylesEnd || memcmp(stylesEnd.unsafe_ptr(), &endSpan, sizeof(endSpan)) != 0) {
ALOGW("Bad string block: last style is not 0xFFFFFFFF-terminated\n");
return (mError=BAD_TYPE);
}
@@ -653,7 +669,7 @@
void ResStringPool::uninit()
{
mError = NO_INIT;
- if (mHeader != NULL && mCache != NULL) {
+ if (mHeader && mCache != NULL) {
for (size_t x = 0; x < mHeader->stringCount; x++) {
if (mCache[x] != NULL) {
free(mCache[x]);
@@ -679,15 +695,21 @@
* data encoded. In that case, drop the high bit of the first character and
* add it together with the next character.
*/
-static inline size_t
-decodeLength(const uint16_t** str)
+static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint16_t>* str)
{
- size_t len = **str;
- if ((len & 0x8000) != 0) {
- (*str)++;
- len = ((len & 0x7FFF) << 16) | **str;
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- (*str)++;
+
+ size_t len = str->value();
+ if ((len & 0x8000U) != 0) {
+ ++(*str);
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ len = ((len & 0x7FFFU) << 16U) | str->value();
+ }
+ ++(*str);
return len;
}
@@ -701,82 +723,119 @@
* data encoded. In that case, drop the high bit of the first character and
* add it together with the next character.
*/
-static inline size_t
-decodeLength(const uint8_t** str)
+static inline base::expected<size_t, IOError> decodeLength(incfs::map_ptr<uint8_t>* str)
{
- size_t len = **str;
- if ((len & 0x80) != 0) {
- (*str)++;
- len = ((len & 0x7F) << 8) | **str;
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- (*str)++;
+
+ size_t len = str->value();
+ if ((len & 0x80U) != 0) {
+ ++(*str);
+ if (UNLIKELY(!*str)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ len = ((len & 0x7FU) << 8U) | str->value();
+ }
+ ++(*str);
return len;
}
-const char16_t* ResStringPool::stringAt(size_t idx, size_t* u16len) const
+base::expected<StringPiece16, NullOrIOError> ResStringPool::stringAt(size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
const bool isUTF8 = (mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0;
- const uint32_t off = mEntries[idx]/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
+ auto offPtr = mEntries + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = (offPtr.value())/(isUTF8?sizeof(uint8_t):sizeof(uint16_t));
if (off < (mStringPoolSize-1)) {
if (!isUTF8) {
- const uint16_t* strings = (uint16_t*)mStrings;
- const uint16_t* str = strings+off;
+ auto strings = mStrings.convert<uint16_t>();
+ auto str = strings+off;
- *u16len = decodeLength(&str);
+ const base::expected<size_t, IOError> u16len = decodeLength(&str);
+ if (UNLIKELY(!u16len.has_value())) {
+ return base::unexpected(u16len.error());
+ }
+
if ((uint32_t)(str+*u16len-strings) < mStringPoolSize) {
// Reject malformed (non null-terminated) strings
- if (str[*u16len] != 0x0000) {
- ALOGW("Bad string block: string #%d is not null-terminated",
- (int)idx);
- return NULL;
+ const auto nullAddress = str + (*u16len);
+ if (UNLIKELY(!nullAddress)) {
+ return base::unexpected(IOError::PAGES_MISSING);
}
- return reinterpret_cast<const char16_t*>(str);
+
+ if (nullAddress.value() != 0x0000) {
+ ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
+ return base::unexpected(std::nullopt);
+ }
+
+ if (UNLIKELY(!str.verify(*u16len + 1U))) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ return StringPiece16(reinterpret_cast<const char16_t*>(str.unsafe_ptr()),
+ *u16len);
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
(int)idx, (int)(str+*u16len-strings), (int)mStringPoolSize);
}
} else {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* u8str = strings+off;
+ auto strings = mStrings.convert<uint8_t>();
+ auto u8str = strings+off;
- *u16len = decodeLength(&u8str);
- size_t u8len = decodeLength(&u8str);
+ base::expected<size_t, IOError> u16len = decodeLength(&u8str);
+ if (UNLIKELY(!u16len.has_value())) {
+ return base::unexpected(u16len.error());
+ }
+
+ const base::expected<size_t, IOError> u8len = decodeLength(&u8str);
+ if (UNLIKELY(!u8len.has_value())) {
+ return base::unexpected(u8len.error());
+ }
// encLen must be less than 0x7FFF due to encoding.
- if ((uint32_t)(u8str+u8len-strings) < mStringPoolSize) {
+ if ((uint32_t)(u8str+*u8len-strings) < mStringPoolSize) {
AutoMutex lock(mDecodeLock);
if (mCache != NULL && mCache[idx] != NULL) {
- return mCache[idx];
+ return StringPiece16(mCache[idx], *u16len);
}
// Retrieve the actual length of the utf8 string if the
// encoded length was truncated
- if (stringDecodeAt(idx, u8str, u8len, &u8len) == NULL) {
- return NULL;
+ auto decodedString = stringDecodeAt(idx, u8str, *u8len);
+ if (!decodedString.has_value()) {
+ return base::unexpected(decodedString.error());
}
// Since AAPT truncated lengths longer than 0x7FFF, check
// that the bits that remain after truncation at least match
// the bits of the actual length
- ssize_t actualLen = utf8_to_utf16_length(u8str, u8len);
- if (actualLen < 0 || ((size_t)actualLen & 0x7FFF) != *u16len) {
+ ssize_t actualLen = utf8_to_utf16_length(
+ reinterpret_cast<const uint8_t*>(decodedString->data()),
+ decodedString->size());
+
+ if (actualLen < 0 || ((size_t)actualLen & 0x7FFFU) != *u16len) {
ALOGW("Bad string block: string #%lld decoded length is not correct "
"%lld vs %llu\n",
(long long)idx, (long long)actualLen, (long long)*u16len);
- return NULL;
+ return base::unexpected(std::nullopt);
}
- *u16len = (size_t) actualLen;
- char16_t *u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
+ u16len = (size_t) actualLen;
+ auto u16str = (char16_t *)calloc(*u16len+1, sizeof(char16_t));
if (!u16str) {
ALOGW("No memory when trying to allocate decode cache for string #%d\n",
(int)idx);
- return NULL;
+ return base::unexpected(std::nullopt);
}
- utf8_to_utf16(u8str, u8len, u16str, *u16len + 1);
+ utf8_to_utf16(reinterpret_cast<const uint8_t*>(decodedString->data()),
+ decodedString->size(), u16str, *u16len + 1);
if (mCache == NULL) {
#ifndef __ANDROID__
@@ -793,19 +852,19 @@
if (mCache == NULL) {
ALOGW("No memory trying to allocate decode cache table of %d bytes\n",
(int)(mHeader->stringCount*sizeof(char16_t**)));
- return NULL;
+ return base::unexpected(std::nullopt);
}
}
if (kDebugStringPoolNoisy) {
- ALOGI("Caching UTF8 string: %s", u8str);
+ ALOGI("Caching UTF8 string: %s", u8str.unsafe_ptr());
}
mCache[idx] = u16str;
- return u16str;
+ return StringPiece16(u16str, *u16len);
} else {
ALOGW("Bad string block: string #%lld extends to %lld, past end at %lld\n",
- (long long)idx, (long long)(u8str+u8len-strings),
+ (long long)idx, (long long)(u8str+*u8len-strings),
(long long)mStringPoolSize);
}
}
@@ -815,33 +874,43 @@
(int)(mStringPoolSize*sizeof(uint16_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
-const char* ResStringPool::string8At(size_t idx, size_t* outLen) const
+base::expected<StringPiece, NullOrIOError> ResStringPool::string8At(size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->stringCount) {
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) == 0) {
- return NULL;
+ return base::unexpected(std::nullopt);
}
- const uint32_t off = mEntries[idx]/sizeof(char);
+
+ auto offPtr = mEntries + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = (offPtr.value())/sizeof(char);
if (off < (mStringPoolSize-1)) {
- const uint8_t* strings = (uint8_t*)mStrings;
- const uint8_t* str = strings+off;
+ auto strings = mStrings.convert<uint8_t>();
+ auto str = strings+off;
// Decode the UTF-16 length. This is not used if we're not
// converting to UTF-16 from UTF-8.
- decodeLength(&str);
+ const base::expected<size_t, IOError> u16len = decodeLength(&str);
+ if (UNLIKELY(!u16len)) {
+ return base::unexpected(u16len.error());
+ }
- const size_t encLen = decodeLength(&str);
- *outLen = encLen;
+ const base::expected<size_t, IOError> u8len = decodeLength(&str);
+ if (UNLIKELY(!u8len)) {
+ return base::unexpected(u8len.error());
+ }
- if ((uint32_t)(str+encLen-strings) < mStringPoolSize) {
- return stringDecodeAt(idx, str, encLen, outLen);
-
+ if ((uint32_t)(str+*u8len-strings) < mStringPoolSize) {
+ return stringDecodeAt(idx, str, *u8len);
} else {
ALOGW("Bad string block: string #%d extends to %d, past end at %d\n",
- (int)idx, (int)(str+encLen-strings), (int)mStringPoolSize);
+ (int)idx, (int)(str+*u8len-strings), (int)mStringPoolSize);
}
} else {
ALOGW("Bad string block: string #%d entry is at %d, past end at %d\n",
@@ -849,7 +918,7 @@
(int)(mStringPoolSize*sizeof(uint16_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
/**
@@ -859,74 +928,93 @@
* bits. Strings that exceed the maximum encode length are not placed into
* StringPools in AAPT2.
**/
-const char* ResStringPool::stringDecodeAt(size_t idx, const uint8_t* str,
- const size_t encLen, size_t* outLen) const {
- const uint8_t* strings = (uint8_t*)mStrings;
-
+base::expected<StringPiece, NullOrIOError> ResStringPool::stringDecodeAt(
+ size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const
+{
+ const auto strings = mStrings.convert<uint8_t>();
size_t i = 0, end = encLen;
while ((uint32_t)(str+end-strings) < mStringPoolSize) {
- if (str[end] == 0x00) {
+ const auto nullAddress = str + end;
+ if (UNLIKELY(!nullAddress)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ if (nullAddress.value() == 0x00) {
if (i != 0) {
ALOGW("Bad string block: string #%d is truncated (actual length is %d)",
(int)idx, (int)end);
}
- *outLen = end;
- return (const char*)str;
+ if (UNLIKELY(!str.verify(end + 1U))) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ return StringPiece((const char*) str.unsafe_ptr(), end);
}
end = (++i << (sizeof(uint8_t) * 8 * 2 - 1)) | encLen;
}
// Reject malformed (non null-terminated) strings
- ALOGW("Bad string block: string #%d is not null-terminated",
- (int)idx);
- return NULL;
+ ALOGW("Bad string block: string #%d is not null-terminated", (int)idx);
+ return base::unexpected(std::nullopt);
}
-const String8 ResStringPool::string8ObjectAt(size_t idx) const
+base::expected<String8, IOError> ResStringPool::string8ObjectAt(size_t idx) const
{
- size_t len;
- const char *str = string8At(idx, &len);
- if (str != NULL) {
- return String8(str, len);
+ const base::expected<StringPiece, NullOrIOError> str = string8At(idx);
+ if (UNLIKELY(IsIOError(str))) {
+ return base::unexpected(GetIOError(str.error()));
+ }
+ if (str.has_value()) {
+ return String8(str->data(), str->size());
}
- const char16_t *str16 = stringAt(idx, &len);
- if (str16 != NULL) {
- return String8(str16, len);
+ const base::expected<StringPiece16, NullOrIOError> str16 = stringAt(idx);
+ if (UNLIKELY(IsIOError(str16))) {
+ return base::unexpected(GetIOError(str16.error()));
}
+ if (str16.has_value()) {
+ return String8(str16->data(), str16->size());
+ }
+
return String8();
}
-const ResStringPool_span* ResStringPool::styleAt(const ResStringPool_ref& ref) const
+base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
+ const ResStringPool_ref& ref) const
{
return styleAt(ref.index);
}
-const ResStringPool_span* ResStringPool::styleAt(size_t idx) const
+base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> ResStringPool::styleAt(
+ size_t idx) const
{
if (mError == NO_ERROR && idx < mHeader->styleCount) {
- const uint32_t off = (mEntryStyles[idx]/sizeof(uint32_t));
+ auto offPtr = mEntryStyles + idx;
+ if (UNLIKELY(!offPtr)) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+
+ const uint32_t off = ((offPtr.value())/sizeof(uint32_t));
if (off < mStylePoolSize) {
- return (const ResStringPool_span*)(mStyles+off);
+ return (mStyles+off).convert<ResStringPool_span>();
} else {
ALOGW("Bad string block: style #%d entry is at %d, past end at %d\n",
(int)idx, (int)(off*sizeof(uint32_t)),
(int)(mStylePoolSize*sizeof(uint32_t)));
}
}
- return NULL;
+ return base::unexpected(std::nullopt);
}
-ssize_t ResStringPool::indexOfString(const char16_t* str, size_t strLen) const
+base::expected<size_t, NullOrIOError> ResStringPool::indexOfString(const char16_t* str,
+ size_t strLen) const
{
if (mError != NO_ERROR) {
- return mError;
+ return base::unexpected(std::nullopt);
}
- size_t len;
-
if ((mHeader->flags&ResStringPool_header::UTF8_FLAG) != 0) {
if (kDebugStringPoolNoisy) {
ALOGI("indexOfString UTF-8: %s", String8(str, strLen).string());
@@ -948,17 +1036,19 @@
ssize_t mid;
while (l <= h) {
mid = l + (h - l)/2;
- const uint8_t* s = (const uint8_t*)string8At(mid, &len);
- int c;
- if (s != NULL) {
- char16_t* end = utf8_to_utf16(s, len, convBuffer, convBufferLen);
+ int c = -1;
+ const base::expected<StringPiece, NullOrIOError> s = string8At(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ if (s.has_value()) {
+ char16_t* end = utf8_to_utf16(reinterpret_cast<const uint8_t*>(s->data()),
+ s->size(), convBuffer, convBufferLen);
c = strzcmp16(convBuffer, end-convBuffer, str, strLen);
- } else {
- c = -1;
}
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- (const char*)s, c, (int)l, (int)mid, (int)h);
+ s->data(), c, (int)l, (int)mid, (int)h);
}
if (c == 0) {
if (kDebugStringPoolNoisy) {
@@ -981,15 +1071,21 @@
String8 str8(str, strLen);
const size_t str8Len = str8.size();
for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char* s = string8At(i, &len);
- if (kDebugStringPoolNoisy) {
- ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+ const base::expected<StringPiece, NullOrIOError> s = string8At(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
}
- if (s && str8Len == len && memcmp(s, str8.string(), str8Len) == 0) {
+ if (s.has_value()) {
if (kDebugStringPoolNoisy) {
- ALOGI("MATCH!");
+ ALOGI("Looking at %s, i=%d\n", s->data(), i);
}
- return i;
+ if (str8Len == s->size()
+ && memcmp(s->data(), str8.string(), str8Len) == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("MATCH!");
+ }
+ return i;
+ }
}
}
}
@@ -1007,11 +1103,14 @@
ssize_t mid;
while (l <= h) {
mid = l + (h - l)/2;
- const char16_t* s = stringAt(mid, &len);
- int c = s ? strzcmp16(s, len, str, strLen) : -1;
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(mid);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
+ }
+ int c = s.has_value() ? strzcmp16(s->data(), s->size(), str, strLen) : -1;
if (kDebugStringPoolNoisy) {
ALOGI("Looking at %s, cmp=%d, l/mid/h=%d/%d/%d\n",
- String8(s).string(), c, (int)l, (int)mid, (int)h);
+ String8(s->data(), s->size()).string(), c, (int)l, (int)mid, (int)h);
}
if (c == 0) {
if (kDebugStringPoolNoisy) {
@@ -1030,11 +1129,15 @@
// span tags; since those always appear at the end of the string
// block, start searching at the back.
for (int i=mHeader->stringCount-1; i>=0; i--) {
- const char16_t* s = stringAt(i, &len);
- if (kDebugStringPoolNoisy) {
- ALOGI("Looking at %s, i=%d\n", String8(s).string(), i);
+ const base::expected<StringPiece16, NullOrIOError> s = stringAt(i);
+ if (UNLIKELY(IsIOError(s))) {
+ return base::unexpected(s.error());
}
- if (s && strLen == len && strzcmp16(s, len, str, strLen) == 0) {
+ if (kDebugStringPoolNoisy) {
+ ALOGI("Looking at %s, i=%d\n", String8(s->data(), s->size()).string(), i);
+ }
+ if (s.has_value() && strLen == s->size() &&
+ strzcmp16(s->data(), s->size(), str, strLen) == 0) {
if (kDebugStringPoolNoisy) {
ALOGI("MATCH!");
}
@@ -1043,8 +1146,7 @@
}
}
}
-
- return NAME_NOT_FOUND;
+ return base::unexpected(std::nullopt);
}
size_t ResStringPool::size() const
@@ -1062,9 +1164,10 @@
return (mError == NO_ERROR) ? mHeader->header.size : 0;
}
-const void* ResStringPool::data() const
+incfs::map_ptr<void> ResStringPool::data() const
{
- return mHeader;
+
+ return mHeader.unsafe_ptr();
}
bool ResStringPool::isSorted() const
@@ -1121,7 +1224,7 @@
const char16_t* ResXMLParser::getComment(size_t* outLen) const
{
int32_t id = getCommentID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
uint32_t ResXMLParser::getLineNumber() const
@@ -1140,7 +1243,7 @@
const char16_t* ResXMLParser::getText(size_t* outLen) const
{
int32_t id = getTextID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
ssize_t ResXMLParser::getTextValue(Res_value* outValue) const
@@ -1164,7 +1267,7 @@
{
int32_t id = getNamespacePrefixID();
//printf("prefix=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getNamespaceUriID() const
@@ -1179,7 +1282,7 @@
{
int32_t id = getNamespaceUriID();
//printf("uri=%d event=%p\n", id, mEventCode);
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getElementNamespaceID() const
@@ -1196,7 +1299,7 @@
const char16_t* ResXMLParser::getElementNamespace(size_t* outLen) const
{
int32_t id = getElementNamespaceID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getElementNameID() const
@@ -1213,7 +1316,7 @@
const char16_t* ResXMLParser::getElementName(size_t* outLen) const
{
int32_t id = getElementNameID();
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
size_t ResXMLParser::getAttributeCount() const
@@ -1246,7 +1349,7 @@
if (kDebugXMLNoisy) {
printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
const char* ResXMLParser::getAttributeNamespace8(size_t idx, size_t* outLen) const
@@ -1256,7 +1359,7 @@
if (kDebugXMLNoisy) {
printf("getAttributeNamespace 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
}
int32_t ResXMLParser::getAttributeNameID(size_t idx) const
@@ -1281,7 +1384,7 @@
if (kDebugXMLNoisy) {
printf("getAttributeName 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
const char* ResXMLParser::getAttributeName8(size_t idx, size_t* outLen) const
@@ -1291,7 +1394,7 @@
if (kDebugXMLNoisy) {
printf("getAttributeName 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.string8At(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.string8At(id), outLen) : NULL;
}
uint32_t ResXMLParser::getAttributeNameResID(size_t idx) const
@@ -1328,7 +1431,7 @@
if (kDebugXMLNoisy) {
printf("getAttributeValue 0x%zx=0x%x\n", idx, id);
}
- return id >= 0 ? mTree.mStrings.stringAt(id, outLen) : NULL;
+ return id >= 0 ? UnpackOptionalString(mTree.mStrings.stringAt(id), outLen) : NULL;
}
int32_t ResXMLParser::getAttributeDataType(size_t idx) const
@@ -3596,9 +3699,10 @@
ssize_t findType16(const char16_t* type, size_t len) const {
const size_t N = packages.size();
for (size_t i = 0; i < N; i++) {
- ssize_t index = packages[i]->typeStrings.indexOfString(type, len);
- if (index >= 0) {
- return index + packages[i]->typeIdOffset;
+ const base::expected<size_t, NullOrIOError> index =
+ packages[i]->typeStrings.indexOfString(type, len);
+ if (index.has_value()) {
+ return *index + packages[i]->typeIdOffset;
}
}
return -1;
@@ -4304,21 +4408,21 @@
outName->package = grp->name.string();
outName->packageLen = grp->name.size();
if (allowUtf8) {
- outName->type8 = entry.typeStr.string8(&outName->typeLen);
- outName->name8 = entry.keyStr.string8(&outName->nameLen);
+ outName->type8 = UnpackOptionalString(entry.typeStr.string8(), &outName->typeLen);
+ outName->name8 = UnpackOptionalString(entry.keyStr.string8(), &outName->nameLen);
} else {
outName->type8 = NULL;
outName->name8 = NULL;
}
if (outName->type8 == NULL) {
- outName->type = entry.typeStr.string16(&outName->typeLen);
+ outName->type = UnpackOptionalString(entry.typeStr.string16(), &outName->typeLen);
// If we have a bad index for some reason, we should abort.
if (outName->type == NULL) {
return false;
}
}
if (outName->name8 == NULL) {
- outName->name = entry.keyStr.string16(&outName->nameLen);
+ outName->name = UnpackOptionalString(entry.keyStr.string16(), &outName->nameLen);
// If we have a bad index for some reason, we should abort.
if (outName->name == NULL) {
return false;
@@ -4406,7 +4510,8 @@
entry.package->header->index,
outValue->dataType,
outValue->dataType == Res_value::TYPE_STRING ?
- String8(entry.package->header->values.stringAt(outValue->data, &len)).string() :
+ String8(UnpackOptionalString(
+ entry.package->header->values.stringAt(outValue->data), &len)).string() :
"",
outValue->data);
}
@@ -4462,7 +4567,8 @@
return NULL;
}
if (value->dataType == value->TYPE_STRING) {
- return getTableStringBlock(stringBlock)->stringAt(value->data, outLen);
+ return UnpackOptionalString(getTableStringBlock(stringBlock)->stringAt(value->data),
+ outLen);
}
// XXX do int to string conversions.
return NULL;
@@ -4978,15 +5084,13 @@
size_t targetTypeLen = typeLen;
do {
- ssize_t ti = group->packages[pi]->typeStrings.indexOfString(
- targetType, targetTypeLen);
- if (ti < 0) {
+ auto ti = group->packages[pi]->typeStrings.indexOfString(targetType, targetTypeLen);
+ if (!ti.has_value()) {
continue;
}
- ti += group->packages[pi]->typeIdOffset;
-
- const uint32_t identifier = findEntry(group, ti, name, nameLen,
+ *ti += group->packages[pi]->typeIdOffset;
+ const uint32_t identifier = findEntry(group, *ti, name, nameLen,
outTypeSpecFlags);
if (identifier != 0) {
if (fakePublic && outTypeSpecFlags) {
@@ -5009,8 +5113,9 @@
const size_t typeCount = typeList.size();
for (size_t i = 0; i < typeCount; i++) {
const Type* t = typeList[i];
- const ssize_t ei = t->package->keyStrings.indexOfString(name, nameLen);
- if (ei < 0) {
+ const base::expected<size_t, NullOrIOError> ei =
+ t->package->keyStrings.indexOfString(name, nameLen);
+ if (!ei.has_value()) {
continue;
}
@@ -5025,7 +5130,7 @@
continue;
}
- if (dtohl(entry->key.index) == (size_t) ei) {
+ if (dtohl(entry->key.index) == (size_t) *ei) {
uint32_t resId = Res_MAKEID(group->id - 1, typeIndex, iter.index());
if (outTypeSpecFlags) {
Entry result;
@@ -6187,8 +6292,9 @@
for (size_t k = 0; k < numTypes; k++) {
const Type* type = typeList[k];
const ResStringPool& typeStrings = type->package->typeStrings;
- if (ignoreMipmap && typeStrings.string8ObjectAt(
- type->typeSpec->id - 1) == "mipmap") {
+ const base::expected<String8, NullOrIOError> typeStr = typeStrings.string8ObjectAt(
+ type->typeSpec->id - 1);
+ if (ignoreMipmap && typeStr.has_value() && *typeStr == "mipmap") {
continue;
}
@@ -6244,24 +6350,18 @@
StringPoolRef::StringPoolRef(const ResStringPool* pool, uint32_t index)
: mPool(pool), mIndex(index) {}
-const char* StringPoolRef::string8(size_t* outLen) const {
- if (mPool != NULL) {
- return mPool->string8At(mIndex, outLen);
+base::expected<StringPiece, NullOrIOError> StringPoolRef::string8() const {
+ if (LIKELY(mPool != NULL)) {
+ return mPool->string8At(mIndex);
}
- if (outLen != NULL) {
- *outLen = 0;
- }
- return NULL;
+ return base::unexpected(std::nullopt);
}
-const char16_t* StringPoolRef::string16(size_t* outLen) const {
- if (mPool != NULL) {
- return mPool->stringAt(mIndex, outLen);
+base::expected<StringPiece16, NullOrIOError> StringPoolRef::string16() const {
+ if (LIKELY(mPool != NULL)) {
+ return mPool->stringAt(mIndex);
}
- if (outLen != NULL) {
- *outLen = 0;
- }
- return NULL;
+ return base::unexpected(std::nullopt);
}
bool ResTable::getResourceFlags(uint32_t resID, uint32_t* outFlags) const {
@@ -7380,13 +7480,13 @@
printf("(dynamic attribute) 0x%08x\n", value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
size_t len;
- const char* str8 = pkg->header->values.string8At(
- value.data, &len);
+ const char* str8 = UnpackOptionalString(pkg->header->values.string8At(
+ value.data), &len);
if (str8 != NULL) {
printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
} else {
- const char16_t* str16 = pkg->header->values.stringAt(
- value.data, &len);
+ const char16_t* str16 = UnpackOptionalString(pkg->header->values.stringAt(
+ value.data), &len);
if (str16 != NULL) {
printf("(string16) \"%s\"\n",
normalizeForOutput(String8(str16, len).string()).string());
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index c63dff8..a34aa72 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -48,61 +48,76 @@
!(has_type_separator && out_type->empty());
}
-bool ToResourceName(const StringPoolRef& type_string_ref,
- const StringPoolRef& entry_string_ref,
- const StringPiece& package_name,
- AssetManager2::ResourceName* out_name) {
- out_name->package = package_name.data();
- out_name->package_len = package_name.size();
+base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
+ const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
+ const StringPiece& package_name) {
+ AssetManager2::ResourceName name{
+ .package = package_name.data(),
+ .package_len = package_name.size(),
+ };
- out_name->type = type_string_ref.string8(&out_name->type_len);
- out_name->type16 = nullptr;
- if (out_name->type == nullptr) {
- out_name->type16 = type_string_ref.string16(&out_name->type_len);
- if (out_name->type16 == nullptr) {
- return false;
+ if (base::expected<StringPiece, NullOrIOError> type_str = type_string_ref.string8()) {
+ name.type = type_str->data();
+ name.type_len = type_str->size();
+ } else if (UNLIKELY(IsIOError(type_str))) {
+ return base::unexpected(type_str.error());
+ }
+
+ if (name.type == nullptr) {
+ if (base::expected<StringPiece16, NullOrIOError> type16_str = type_string_ref.string16()) {
+ name.type16 = type16_str->data();
+ name.type_len = type16_str->size();
+ } else if (!type16_str.has_value()) {
+ return base::unexpected(type16_str.error());
}
}
- out_name->entry = entry_string_ref.string8(&out_name->entry_len);
- out_name->entry16 = nullptr;
- if (out_name->entry == nullptr) {
- out_name->entry16 = entry_string_ref.string16(&out_name->entry_len);
- if (out_name->entry16 == nullptr) {
- return false;
+ if (base::expected<StringPiece, NullOrIOError> entry_str = entry_string_ref.string8()) {
+ name.entry = entry_str->data();
+ name.entry_len = entry_str->size();
+ } else if (UNLIKELY(IsIOError(entry_str))) {
+ return base::unexpected(entry_str.error());
+ }
+
+ if (name.entry == nullptr) {
+ if (base::expected<StringPiece16, NullOrIOError> entry16_str = entry_string_ref.string16()) {
+ name.entry16 = entry16_str->data();
+ name.entry_len = entry16_str->size();
+ } else if (!entry16_str.has_value()) {
+ return base::unexpected(entry16_str.error());
}
}
- return true;
+ return name;
}
-std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) {
+std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name) {
std::string result;
- if (resource_name->package != nullptr) {
- result.append(resource_name->package, resource_name->package_len);
+ if (resource_name.package != nullptr) {
+ result.append(resource_name.package, resource_name.package_len);
}
- if (resource_name->type != nullptr || resource_name->type16 != nullptr) {
+ if (resource_name.type != nullptr || resource_name.type16 != nullptr) {
if (!result.empty()) {
result += ":";
}
- if (resource_name->type != nullptr) {
- result.append(resource_name->type, resource_name->type_len);
+ if (resource_name.type != nullptr) {
+ result.append(resource_name.type, resource_name.type_len);
} else {
- result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len));
+ result += util::Utf16ToUtf8(StringPiece16(resource_name.type16, resource_name.type_len));
}
}
- if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) {
+ if (resource_name.entry != nullptr || resource_name.entry16 != nullptr) {
if (!result.empty()) {
result += "/";
}
- if (resource_name->entry != nullptr) {
- result.append(resource_name->entry, resource_name->entry_len);
+ if (resource_name.entry != nullptr) {
+ result.append(resource_name.entry, resource_name.entry_len);
} else {
- result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len));
+ result += util::Utf16ToUtf8(StringPiece16(resource_name.entry16, resource_name.entry_len));
}
}
diff --git a/libs/androidfw/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
index b39b5f0..1c5e5d4 100644
--- a/libs/androidfw/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -70,13 +70,13 @@
/*
* Streaming access to compressed data held in an mmapped region of memory
*/
-StreamingZipInflater::StreamingZipInflater(FileMap* dataMap, size_t uncompSize) {
+StreamingZipInflater::StreamingZipInflater(const incfs::IncFsFileMap* dataMap, size_t uncompSize) {
mFd = -1;
mDataMap = dataMap;
mOutTotalSize = uncompSize;
- mInTotalSize = dataMap->getDataLength();
+ mInTotalSize = dataMap->length();
- mInBuf = (uint8_t*) dataMap->getDataPtr();
+ mInBuf = (uint8_t*) dataMap->unsafe_data(); // IncFs safety handled in zlib.
mInBufSize = mInTotalSize;
mOutBufSize = StreamingZipInflater::OUTPUT_CHUNK_SIZE;
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index e77ac3d..52e7a70 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -233,6 +233,29 @@
}
/*
+ * Create a new incfs::IncFsFileMap object that spans the data in "entry".
+ */
+std::optional<incfs::IncFsFileMap> ZipFileRO::createEntryIncFsFileMap(ZipEntryRO entry) const
+{
+ const _ZipEntryRO *zipEntry = reinterpret_cast<_ZipEntryRO*>(entry);
+ const ZipEntry& ze = zipEntry->entry;
+ int fd = GetFileDescriptor(mHandle);
+ size_t actualLen = 0;
+
+ if (ze.method == kCompressStored) {
+ actualLen = ze.uncompressed_length;
+ } else {
+ actualLen = ze.compressed_length;
+ }
+
+ incfs::IncFsFileMap newMap;
+ if (!newMap.Create(fd, ze.offset, actualLen, mFileName)) {
+ return std::nullopt;
+ }
+ return std::move(newMap);
+}
+
+/*
* Uncompress an entry, in its entirety, into the provided output buffer.
*
* This doesn't verify the data's CRC, which might be useful for
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 568e3b6..58fc5bb 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -40,7 +40,7 @@
explicit FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
// Data is usually requested sequentially, so this helps avoid pointless
// fseeks every time we perform a read. There's an impedence mismatch
// here because the original API was designed around pread and pwrite.
@@ -71,7 +71,7 @@
explicit FdReader(int fd) : mFd(fd) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
return android::base::ReadFullyAtOffset(mFd, buf, len, offset);
}
@@ -81,22 +81,27 @@
class BufferReader : public zip_archive::Reader {
public:
- BufferReader(const void* input, size_t inputSize) : Reader(),
- mInput(reinterpret_cast<const uint8_t*>(input)),
+ BufferReader(incfs::map_ptr<void> input, size_t inputSize) : Reader(),
+ mInput(input.convert<uint8_t>()),
mInputSize(inputSize) {
}
- bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const {
+ bool ReadAtOffset(uint8_t* buf, size_t len, off64_t offset) const override {
if (mInputSize < len || offset > mInputSize - len) {
return false;
}
- memcpy(buf, mInput + offset, len);
+ const incfs::map_ptr<uint8_t> pos = mInput.offset(offset);
+ if (!pos.verify(len)) {
+ return false;
+ }
+
+ memcpy(buf, pos.unsafe_ptr(), len);
return true;
}
private:
- const uint8_t* mInput;
+ const incfs::map_ptr<uint8_t> mInput;
const size_t mInputSize;
};
@@ -138,7 +143,7 @@
return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf,
+/*static*/ bool ZipUtils::inflateToBuffer(incfs::map_ptr<void> in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
diff --git a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
index 96d44ab..5309ab2 100644
--- a/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
+++ b/libs/androidfw/fuzz/resourcefile_fuzzer/resourcefile_fuzzer.cpp
@@ -31,9 +31,6 @@
using android::StringPiece;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-
- std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(reinterpret_cast<const char*>(data), size));
-
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(data, size);
return 0;
}
\ No newline at end of file
diff --git a/libs/androidfw/include/androidfw/Asset.h b/libs/androidfw/include/androidfw/Asset.h
index 298509e..80bae20 100644
--- a/libs/androidfw/include/androidfw/Asset.h
+++ b/libs/androidfw/include/androidfw/Asset.h
@@ -23,18 +23,18 @@
#include <stdio.h>
#include <sys/types.h>
-
#include <memory>
+#include <optional>
#include <android-base/unique_fd.h>
+#include <util/map_ptr.h>
+
#include <utils/Compat.h>
#include <utils/Errors.h>
#include <utils/String8.h>
namespace android {
-class FileMap;
-
/*
* Instances of this class provide read-only operations on a byte stream.
*
@@ -49,6 +49,8 @@
class Asset {
public:
virtual ~Asset(void) = default;
+ Asset(const Asset& src) = delete;
+ Asset& operator=(const Asset& src) = delete;
static int32_t getGlobalCount();
static String8 getAssetAllocations();
@@ -87,8 +89,19 @@
/*
* Get a pointer to a buffer with the entire contents of the file.
+ * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary.
+ *
+ * Use this function if the asset can never reside on IncFs.
*/
- virtual const void* getBuffer(bool wordAligned) = 0;
+ virtual const void* getBuffer(bool aligned) = 0;
+
+ /*
+ * Get a incfs::map_ptr<void> to a buffer with the entire contents of the file.
+ * If `aligned` is true, the buffer data will be aligned to a 4-byte boundary.
+ *
+ * Use this function if the asset can potentially reside on IncFs.
+ */
+ virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned) = 0;
/*
* Get the total amount of data that can be read.
@@ -152,10 +165,6 @@
AccessMode getAccessMode(void) const { return mAccessMode; }
private:
- /* these operations are not implemented */
- Asset(const Asset& src);
- Asset& operator=(const Asset& src);
-
/* AssetManager needs access to our "create" functions */
friend class AssetManager;
friend class ApkAssets;
@@ -169,8 +178,7 @@
/*
* Create the asset from a named, compressed file on disk (e.g. ".gz").
*/
- static Asset* createFromCompressedFile(const char* fileName,
- AccessMode mode);
+ static Asset* createFromCompressedFile(const char* fileName, AccessMode mode);
#if 0
/*
@@ -200,31 +208,21 @@
/*
* Create the asset from a memory-mapped file segment.
*
- * The asset takes ownership of the FileMap.
+ * The asset takes ownership of the incfs::IncFsFileMap and the file descriptor "fd". The
+ * file descriptor is used to request new file descriptors using "openFileDescriptor".
*/
- static Asset* createFromUncompressedMap(FileMap* dataMap, AccessMode mode);
-
- /*
- * Create the asset from a memory-mapped file segment.
- *
- * The asset takes ownership of the FileMap and the file descriptor "fd". The file descriptor is
- * used to request new file descriptors using "openFileDescriptor".
- */
- static std::unique_ptr<Asset> createFromUncompressedMap(std::unique_ptr<FileMap> dataMap,
- base::unique_fd fd, AccessMode mode);
+ static std::unique_ptr<Asset> createFromUncompressedMap(incfs::IncFsFileMap&& dataMap,
+ AccessMode mode,
+ base::unique_fd fd = {});
/*
* Create the asset from a memory-mapped file segment with compressed
* data.
*
- * The asset takes ownership of the FileMap.
+ * The asset takes ownership of the incfs::IncFsFileMap.
*/
- static Asset* createFromCompressedMap(FileMap* dataMap,
- size_t uncompressedLen, AccessMode mode);
-
- static std::unique_ptr<Asset> createFromCompressedMap(std::unique_ptr<FileMap> dataMap,
- size_t uncompressedLen, AccessMode mode);
-
+ static std::unique_ptr<Asset> createFromCompressedMap(incfs::IncFsFileMap&& dataMap,
+ size_t uncompressedLen, AccessMode mode);
/*
* Create from a reference-counted chunk of shared memory.
@@ -252,7 +250,7 @@
class _FileAsset : public Asset {
public:
_FileAsset(void);
- virtual ~_FileAsset(void);
+ ~_FileAsset(void) override;
/*
* Use a piece of an already-open file.
@@ -266,21 +264,24 @@
*
* On success, the object takes ownership of "dataMap" and "fd".
*/
- status_t openChunk(FileMap* dataMap, base::unique_fd fd);
+ status_t openChunk(incfs::IncFsFileMap&& dataMap, base::unique_fd fd);
/*
* Standard Asset interfaces.
*/
- virtual ssize_t read(void* buf, size_t count);
- virtual off64_t seek(off64_t offset, int whence);
- virtual void close(void);
- virtual const void* getBuffer(bool wordAligned);
- virtual off64_t getLength(void) const { return mLength; }
- virtual off64_t getRemainingLength(void) const { return mLength-mOffset; }
- virtual int openFileDescriptor(off64_t* outStart, off64_t* outLength) const;
- virtual bool isAllocated(void) const { return mBuf != NULL; }
+ ssize_t read(void* buf, size_t count) override;
+ off64_t seek(off64_t offset, int whence) override;
+ void close(void) override;
+ const void* getBuffer(bool aligned) override;
+ incfs::map_ptr<void> getIncFsBuffer(bool aligned) override;
+ off64_t getLength(void) const override { return mLength; }
+ off64_t getRemainingLength(void) const override { return mLength-mOffset; }
+ int openFileDescriptor(off64_t* outStart, off64_t* outLength) const override;
+ bool isAllocated(void) const override { return mBuf != NULL; }
private:
+ incfs::map_ptr<void> ensureAlignment(const incfs::IncFsFileMap& map);
+
off64_t mStart; // absolute file offset of start of chunk
off64_t mLength; // length of the chunk
off64_t mOffset; // current local offset, 0 == mStart
@@ -295,10 +296,8 @@
*/
enum { kReadVsMapThreshold = 4096 };
- FileMap* mMap; // for memory map
- unsigned char* mBuf; // for read
-
- const void* ensureAlignment(FileMap* map);
+ unsigned char* mBuf; // for read
+ std::optional<incfs::IncFsFileMap> mMap; // for memory map
};
@@ -323,7 +322,7 @@
*
* On success, the object takes ownership of "fd".
*/
- status_t openChunk(FileMap* dataMap, size_t uncompressedLen);
+ status_t openChunk(incfs::IncFsFileMap&& dataMap, size_t uncompressedLen);
/*
* Standard Asset interfaces.
@@ -331,24 +330,23 @@
virtual ssize_t read(void* buf, size_t count);
virtual off64_t seek(off64_t offset, int whence);
virtual void close(void);
- virtual const void* getBuffer(bool wordAligned);
+ virtual const void* getBuffer(bool aligned);
+ virtual incfs::map_ptr<void> getIncFsBuffer(bool aligned);
virtual off64_t getLength(void) const { return mUncompressedLen; }
virtual off64_t getRemainingLength(void) const { return mUncompressedLen-mOffset; }
virtual int openFileDescriptor(off64_t* /* outStart */, off64_t* /* outLength */) const { return -1; }
virtual bool isAllocated(void) const { return mBuf != NULL; }
private:
- off64_t mStart; // offset to start of compressed data
- off64_t mCompressedLen; // length of the compressed data
- off64_t mUncompressedLen; // length of the uncompressed data
- off64_t mOffset; // current offset, 0 == start of uncomp data
+ off64_t mStart; // offset to start of compressed data
+ off64_t mCompressedLen; // length of the compressed data
+ off64_t mUncompressedLen; // length of the uncompressed data
+ off64_t mOffset; // current offset, 0 == start of uncomp data
+ int mFd; // for file input
- FileMap* mMap; // for memory-mapped input
- int mFd; // for file input
-
- class StreamingZipInflater* mZipInflater; // for streaming large compressed assets
-
- unsigned char* mBuf; // for getBuffer()
+ class StreamingZipInflater* mZipInflater; // for streaming large compressed assets
+ unsigned char* mBuf; // for getBuffer()
+ std::optional<incfs::IncFsFileMap> mMap; // for memory-mapped input
};
// need: shared mmap version?
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 30ef25c..a92694c 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -131,8 +131,8 @@
bool GetOverlayablesToString(const android::StringPiece& package_name,
std::string* out) const;
- const std::unordered_map<std::string, std::string>*
- GetOverlayableMapForPackage(uint32_t package_id) const;
+ const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(
+ uint32_t package_id) const;
// Returns whether the resources.arsc of any loaded apk assets is allocated in RAM (not mmapped).
bool ContainsAllocatedTable() const;
@@ -145,14 +145,16 @@
return configuration_;
}
- // Returns all configurations for which there are resources defined. This includes resource
- // configurations in all the ApkAssets set for this AssetManager.
+ // Returns all configurations for which there are resources defined, or an I/O error if reading
+ // resource data failed.
+ //
+ // This includes resource configurations in all the ApkAssets set for this AssetManager.
// If `exclude_system` is set to true, resource configurations from system APKs
// ('android' package, other libraries) will be excluded from the list.
// If `exclude_mipmap` is set to true, resource configurations defined for resource type 'mipmap'
// will be excluded from the list.
- std::set<ResTable_config> GetResourceConfigurations(bool exclude_system = false,
- bool exclude_mipmap = false) const;
+ base::expected<std::set<ResTable_config>, IOError> GetResourceConfigurations(
+ bool exclude_system = false, bool exclude_mipmap = false) const;
// Returns all the locales for which there are resources defined. This includes resource
// locales in all the ApkAssets set for this AssetManager.
@@ -194,53 +196,109 @@
std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
Asset::AccessMode mode) const;
- // Populates the `out_name` parameter with resource name information.
- // Utf8 strings are preferred, and only if they are unavailable are
- // the Utf16 variants populated.
- // Returns false if the resource was not found or the name was missing/corrupt.
- bool GetResourceName(uint32_t resid, ResourceName* out_name) const;
-
- // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
- // See ResTable_config for the list of configuration axis.
- // Returns false if the resource was not found.
- bool GetResourceFlags(uint32_t resid, uint32_t* out_flags) const;
+ // Returns the resource name of the specified resource ID.
+ //
+ // Utf8 strings are preferred, and only if they are unavailable are the Utf16 variants populated.
+ //
+ // Returns a null error if the name is missing/corrupt, or an I/O error if reading resource data
+ // failed.
+ base::expected<ResourceName, NullOrIOError> GetResourceName(uint32_t resid) const;
// Finds the resource ID assigned to `resource_name`.
+ //
// `resource_name` must be of the form '[package:][type/]entry'.
// If no package is specified in `resource_name`, then `fallback_package` is used as the package.
// If no type is specified in `resource_name`, then `fallback_type` is used as the type.
- // Returns 0x0 if no resource by that name was found.
- uint32_t GetResourceId(const std::string& resource_name, const std::string& fallback_type = {},
- const std::string& fallback_package = {}) const;
-
- // Retrieves the best matching resource with ID `resid`. The resource value is filled into
- // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
- // `out_flags` holds the same flags as retrieved with GetResourceFlags().
- // If `density_override` is non-zero, the configuration to match against is overridden with that
- // density.
//
- // Returns a valid cookie if the resource was found. If the resource was not found, or if the
- // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false,
- // this function logs if the resource was a map/bag type before returning kInvalidCookie.
- ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
- Res_value* out_value, ResTable_config* out_selected_config,
- uint32_t* out_flags) const;
+ // Returns a null error if no resource by that name was found, or an I/O error if reading resource
+ // data failed.
+ base::expected<uint32_t, NullOrIOError> GetResourceId(
+ const std::string& resource_name, const std::string& fallback_type = {},
+ const std::string& fallback_package = {}) const;
- // Resolves the resource reference in `in_out_value` if the data type is
- // Res_value::TYPE_REFERENCE.
- // `cookie` is the ApkAssetsCookie of the reference in `in_out_value`.
- // `in_out_value` is the reference to resolve. The result is placed back into this object.
- // `in_out_flags` is the type spec flags returned from calls to GetResource() or
- // GetResourceFlags(). Configuration flags of the values pointed to by the reference
- // are OR'd together with `in_out_flags`.
- // `in_out_config` is populated with the configuration for which the resolved value was defined.
- // `out_last_reference` is populated with the last reference ID before resolving to an actual
- // value. This is only initialized if the passed in `in_out_value` is a reference.
- // Returns the cookie of the APK the resolved resource was defined in, or kInvalidCookie if
- // it was not found.
- ApkAssetsCookie ResolveReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config, uint32_t* in_out_flags,
- uint32_t* out_last_reference) const;
+ struct SelectedValue {
+ friend AssetManager2;
+ friend Theme;
+ SelectedValue() = default;
+ SelectedValue(const ResolvedBag* bag, const ResolvedBag::Entry& entry) :
+ cookie(entry.cookie), data(entry.value.data), type(entry.value.dataType),
+ flags(bag->type_spec_flags), resid(0U), config({}) {};
+
+ // The cookie representing the ApkAssets in which the value resides.
+ ApkAssetsCookie cookie = kInvalidCookie;
+
+ // The data for this value, as interpreted according to `type`.
+ Res_value::data_type data;
+
+ // Type of the data value.
+ uint8_t type;
+
+ // The bitmask of configuration axis that this resource varies with.
+ // See ResTable_config::CONFIG_*.
+ uint32_t flags;
+
+ // The resource ID from which this value was resolved.
+ uint32_t resid;
+
+ // The configuration for which the resolved value was defined.
+ ResTable_config config;
+
+ private:
+ SelectedValue(uint8_t value_type, Res_value::data_type value_data, ApkAssetsCookie cookie,
+ uint32_t type_flags, uint32_t resid, const ResTable_config& config) :
+ cookie(cookie), data(value_data), type(value_type), flags(type_flags),
+ resid(resid), config(config) {};
+ };
+
+ // Retrieves the best matching resource value with ID `resid`.
+ //
+ // If `may_be_bag` is false, this function logs if the resource was a map/bag type and returns a
+ // null result. If `density_override` is non-zero, the configuration to match against is
+ // overridden with that density.
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<SelectedValue, NullOrIOError> GetResource(uint32_t resid, bool may_be_bag = false,
+ uint16_t density_override = 0U) const;
+
+ // Resolves the resource referenced in `value` if the type is Res_value::TYPE_REFERENCE.
+ //
+ // If the data type is not Res_value::TYPE_REFERENCE, no work is done. Configuration flags of the
+ // values pointed to by the reference are OR'd into `value.flags`. If `cache_value` is true, then
+ // the resolved value will be cached and used when attempting to resolve the resource id specified
+ // in `value`.
+ //
+ // Returns a null error if the resource could not be resolved, or an I/O error if reading
+ // resource data failed.
+ base::expected<std::monostate, NullOrIOError> ResolveReference(SelectedValue& value,
+ bool cache_value = false) const;
+
+ // Retrieves the best matching bag/map resource with ID `resid`.
+ //
+ // This method will resolve all parent references for this bag and merge keys with the child.
+ // To iterate over the keys, use the following idiom:
+ //
+ // base::expected<const ResolvedBag*, NullOrIOError> bag = asset_manager->GetBag(id);
+ // if (bag.has_value()) {
+ // for (auto iter = begin(*bag); iter != end(*bag); ++iter) {
+ // ...
+ // }
+ // }
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<const ResolvedBag*, NullOrIOError> GetBag(uint32_t resid) const;
+
+ // Retrieves the best matching bag/map resource of the resource referenced in `value`.
+ //
+ // If `value.type` is not Res_value::TYPE_REFERENCE, a null result is returned.
+ // Configuration flags of the bag pointed to by the reference are OR'd into `value.flags`.
+ //
+ // Returns a null error if a best match could not be found, or an I/O error if reading resource
+ // data failed.
+ base::expected<const ResolvedBag*, NullOrIOError> ResolveBag(SelectedValue& value) const;
+
+ const std::vector<uint32_t> GetBagResIdStack(uint32_t resid) const;
// Resets the resource resolution structures in preparation for the next resource retrieval.
void ResetResourceResolution() const;
@@ -252,20 +310,6 @@
// resolved yet.
std::string GetLastResourceResolution() const;
- const std::vector<uint32_t> GetBagResIdStack(uint32_t resid);
-
- // Retrieves the best matching bag/map resource with ID `resid`.
- // This method will resolve all parent references for this bag and merge keys with the child.
- // To iterate over the keys, use the following idiom:
- //
- // const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id);
- // if (bag != nullptr) {
- // for (auto iter = begin(bag); iter != end(bag); ++iter) {
- // ...
- // }
- // }
- const ResolvedBag* GetBag(uint32_t resid);
-
// Creates a new Theme from this AssetManager.
std::unique_ptr<Theme> NewTheme();
@@ -286,11 +330,15 @@
private:
DISALLOW_COPY_AND_ASSIGN(AssetManager2);
+ struct TypeConfig {
+ incfs::verified_map_ptr<ResTable_type> type;
+ ResTable_config config;
+ };
+
// A collection of configurations and their associated ResTable_type that match the current
// AssetManager configuration.
struct FilteredConfigGroup {
- std::vector<ResTable_config> configurations;
- std::vector<const ResTable_type*> types;
+ std::vector<TypeConfig> type_configs;
};
// Represents an single package.
@@ -331,9 +379,7 @@
};
// Finds the best entry for `resid` from the set of ApkAssets. The entry can be a simple
- // Res_value, or a complex map/bag type. If successful, it is available in `out_entry`.
- // Returns kInvalidCookie on failure. Otherwise, the return value is the cookie associated with
- // the ApkAssets in which the entry was found.
+ // Res_value, or a complex map/bag type. Returns a null result if a best entry cannot be found.
//
// `density_override` overrides the density of the current configuration when doing a search.
//
@@ -347,13 +393,15 @@
//
// NOTE: FindEntry takes care of ensuring that structs within FindEntryResult have been properly
// bounds-checked. Callers of FindEntry are free to trust the data if this method succeeds.
- ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
- bool ignore_configuration, FindEntryResult* out_entry) const;
+ base::expected<FindEntryResult, NullOrIOError> FindEntry(uint32_t resid,
+ uint16_t density_override,
+ bool stop_at_first_match,
+ bool ignore_configuration) const;
- ApkAssetsCookie FindEntryInternal(const PackageGroup& package_group, uint8_t type_idx,
- uint16_t entry_idx, const ResTable_config& desired_config,
- bool /*stop_at_first_match*/,
- bool ignore_configuration, FindEntryResult* out_entry) const;
+ base::expected<FindEntryResult, NullOrIOError> FindEntryInternal(
+ const PackageGroup& package_group, uint8_t type_idx, uint16_t entry_idx,
+ const ResTable_config& desired_config, bool stop_at_first_match,
+ bool ignore_configuration) const;
// Assigns package IDs to all shared library ApkAssets.
// Should be called whenever the ApkAssets are changed.
@@ -372,7 +420,8 @@
// AssetManager2::GetBag(resid) wraps this function to track which resource ids have already
// been seen while traversing bag parents.
- const ResolvedBag* GetBag(uint32_t resid, std::vector<uint32_t>& child_resids);
+ base::expected<const ResolvedBag*, NullOrIOError> GetBag(
+ uint32_t resid, std::vector<uint32_t>& child_resids) const;
// The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
// have a longer lifetime.
@@ -394,19 +443,20 @@
// Cached set of bags. These are cached because they can inherit keys from parent bags,
// which involves some calculation.
- std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+ mutable std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
// Cached set of bag resid stacks for each bag. These are cached because they might be requested
// a number of times for each view during View inspection.
- std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+ mutable std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+
+ // Cached set of resolved resource values.
+ mutable std::unordered_map<uint32_t, SelectedValue> cached_resolved_values_;
// Whether or not to save resource resolution steps
bool resource_resolution_logging_enabled_ = false;
struct Resolution {
-
struct Step {
-
enum class Type {
INITIAL,
BETTER_MATCH,
@@ -455,55 +505,53 @@
public:
~Theme();
- // Applies the style identified by `resid` to this theme. This can be called
- // multiple times with different styles. By default, any theme attributes that
- // are already defined before this call are not overridden. If `force` is set
- // to true, this behavior is changed and all theme attributes from the style at
- // `resid` are applied.
- // Returns false if the style failed to apply.
- bool ApplyStyle(uint32_t resid, bool force = false);
+ // Applies the style identified by `resid` to this theme.
+ //
+ // This can be called multiple times with different styles. By default, any theme attributes that
+ // are already defined before this call are not overridden. If `force` is set to true, this
+ // behavior is changed and all theme attributes from the style at `resid` are applied.
+ //
+ // Returns a null error if the style could not be applied, or an I/O error if reading resource
+ // data failed.
+ base::expected<std::monostate, NullOrIOError> ApplyStyle(uint32_t resid, bool force = false);
- // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
- // If `o` does not have the same AssetManager as this theme, only attributes from ApkAssets loaded
- // into both AssetManagers will be copied to this theme.
- void SetTo(const Theme& o);
+ // Sets this Theme to be a copy of `other` if `other` has the same AssetManager as this Theme.
+ //
+ // If `other` does not have the same AssetManager as this theme, only attributes from ApkAssets
+ // loaded into both AssetManagers will be copied to this theme.
+ //
+ // Returns an I/O error if reading resource data failed.
+ base::expected<std::monostate, IOError> SetTo(const Theme& other);
void Clear();
- void Dump() const;
+ // Retrieves the value of attribute ID `resid` in the theme.
+ //
+ // NOTE: This function does not do reference traversal. If you want to follow references to other
+ // resources to get the "real" value to use, you need to call ResolveReference() after this
+ // function.
+ std::optional<AssetManager2::SelectedValue> GetAttribute(uint32_t resid) const;
- inline const AssetManager2* GetAssetManager() const {
+ // This is like AssetManager2::ResolveReference(), but also takes care of resolving attribute
+ // references to the theme.
+ base::expected<std::monostate, NullOrIOError> ResolveAttributeReference(
+ AssetManager2::SelectedValue& value) const;
+
+ AssetManager2* GetAssetManager() {
return asset_manager_;
}
- inline AssetManager2* GetAssetManager() {
+ const AssetManager2* GetAssetManager() const {
return asset_manager_;
}
// Returns a bit mask of configuration changes that will impact this
// theme (and thus require completely reloading it).
- inline uint32_t GetChangingConfigurations() const {
+ uint32_t GetChangingConfigurations() const {
return type_spec_flags_;
}
- // Retrieve a value in the theme. If the theme defines this value, returns an asset cookie
- // indicating which ApkAssets it came from and populates `out_value` with the value.
- // `out_flags` is populated with a bitmask of the configuration axis with which the resource
- // varies.
- //
- // If the attribute is not found, returns kInvalidCookie.
- //
- // NOTE: This function does not do reference traversal. If you want to follow references to other
- // resources to get the "real" value to use, you need to call ResolveReference() after this
- // function.
- ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value, uint32_t* out_flags) const;
-
- // This is like AssetManager2::ResolveReference(), but also takes
- // care of resolving attribute references to the theme.
- ApkAssetsCookie ResolveAttributeReference(ApkAssetsCookie cookie, Res_value* in_out_value,
- ResTable_config* in_out_selected_config = nullptr,
- uint32_t* in_out_type_spec_flags = nullptr,
- uint32_t* out_last_ref = nullptr) const;
+ void Dump() const;
private:
DISALLOW_COPY_AND_ASSIGN(Theme);
diff --git a/libs/androidfw/include/androidfw/AttributeResolution.h b/libs/androidfw/include/androidfw/AttributeResolution.h
index d71aad2..1a69a30 100644
--- a/libs/androidfw/include/androidfw/AttributeResolution.h
+++ b/libs/androidfw/include/androidfw/AttributeResolution.h
@@ -45,20 +45,28 @@
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool ResolveAttrs(Theme* theme, uint32_t def_style_attr, uint32_t def_style_resid,
- uint32_t* src_values, size_t src_values_length, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> ResolveAttrs(Theme* theme, uint32_t def_style_attr,
+ uint32_t def_style_resid, uint32_t* src_values,
+ size_t src_values_length, uint32_t* attrs,
+ size_t attrs_length, uint32_t* out_values,
+ uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` is NOT optional and must NOT be nullptr.
-void ApplyStyle(Theme* theme, ResXMLParser* xml_parser, uint32_t def_style_attr,
- uint32_t def_style_resid, const uint32_t* attrs, size_t attrs_length,
- uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> ApplyStyle(Theme* theme, ResXMLParser* xml_parser,
+ uint32_t def_style_attr,
+ uint32_t def_style_resid,
+ const uint32_t* attrs, size_t attrs_length,
+ uint32_t* out_values, uint32_t* out_indices);
// `out_values` must NOT be nullptr.
// `out_indices` may be nullptr.
-bool RetrieveAttributes(AssetManager2* assetmanager, ResXMLParser* xml_parser, uint32_t* attrs,
- size_t attrs_length, uint32_t* out_values, uint32_t* out_indices);
+base::expected<std::monostate, IOError> RetrieveAttributes(AssetManager2* assetmanager,
+ ResXMLParser* xml_parser,
+ uint32_t* attrs,
+ size_t attrs_length,
+ uint32_t* out_values,
+ uint32_t* out_indices);
} // namespace android
diff --git a/libs/androidfw/include/androidfw/Chunk.h b/libs/androidfw/include/androidfw/Chunk.h
index a0f2343..f1c43b2 100644
--- a/libs/androidfw/include/androidfw/Chunk.h
+++ b/libs/androidfw/include/androidfw/Chunk.h
@@ -36,7 +36,7 @@
// of the chunk.
class Chunk {
public:
- explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {}
+ explicit Chunk(incfs::verified_map_ptr<ResChunk_header> chunk) : device_chunk_(chunk) {}
// Returns the type of the chunk. Caller need not worry about endianness.
inline int type() const { return dtohs(device_chunk_->type); }
@@ -49,21 +49,18 @@
inline size_t header_size() const { return dtohs(device_chunk_->headerSize); }
template <typename T, size_t MinSize = sizeof(T)>
- inline const T* header() const {
- if (header_size() >= MinSize) {
- return reinterpret_cast<const T*>(device_chunk_);
- }
- return nullptr;
+ inline incfs::map_ptr<T> header() const {
+ return (header_size() >= MinSize) ? device_chunk_.convert<T>() : nullptr;
}
- inline const void* data_ptr() const {
- return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size();
+ inline incfs::map_ptr<void> data_ptr() const {
+ return device_chunk_.offset(header_size());
}
inline size_t data_size() const { return size() - header_size(); }
private:
- const ResChunk_header* device_chunk_;
+ const incfs::verified_map_ptr<ResChunk_header> device_chunk_;
};
// Provides a Java style iterator over an array of ResChunk_header's.
@@ -84,11 +81,11 @@
//
class ChunkIterator {
public:
- ChunkIterator(const void* data, size_t len)
- : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)),
+ ChunkIterator(incfs::map_ptr<void> data, size_t len)
+ : next_chunk_(data.convert<ResChunk_header>()),
len_(len),
last_error_(nullptr) {
- CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
+ CHECK((bool) next_chunk_) << "data can't be null";
if (len_ != 0) {
VerifyNextChunk();
}
@@ -113,7 +110,7 @@
// Returns false if there was an error. For legacy purposes.
bool VerifyNextChunkNonFatal();
- const ResChunk_header* next_chunk_;
+ incfs::map_ptr<ResChunk_header> next_chunk_;
size_t len_;
const char* last_error_;
bool last_error_was_fatal_ = true;
diff --git a/libs/androidfw/include/androidfw/Errors.h b/libs/androidfw/include/androidfw/Errors.h
new file mode 100644
index 0000000..948162d
--- /dev/null
+++ b/libs/androidfw/include/androidfw/Errors.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2020 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 ANDROIDFW_ERRORS_H_
+#define ANDROIDFW_ERRORS_H_
+
+#include <optional>
+#include <variant>
+
+#include <android-base/result.h>
+
+namespace android {
+
+enum class IOError {
+ // Used when reading a file residing on an IncFs file-system times out.
+ PAGES_MISSING = -1,
+};
+
+// Represents an absent result or an I/O error.
+using NullOrIOError = std::variant<std::nullopt_t, IOError>;
+
+// Checks whether the result holds an unexpected I/O error.
+template <typename T>
+static inline bool IsIOError(const base::expected<T, NullOrIOError> result) {
+ return !result.has_value() && std::holds_alternative<IOError>(result.error());
+}
+
+static inline IOError GetIOError(const NullOrIOError& error) {
+ return std::get<IOError>(error);
+}
+
+} // namespace android
+
+#endif //ANDROIDFW_ERRORS_H_
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index ab0f47f..fdab03b 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -40,8 +40,8 @@
class OverlayStringPool : public ResStringPool {
public:
virtual ~OverlayStringPool();
- const char16_t* stringAt(size_t idx, size_t* outLen) const override;
- const char* string8At(size_t idx, size_t* outLen) const override;
+ base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const override;
+ base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const override;
size_t size() const override;
explicit OverlayStringPool(const LoadedIdmap* loaded_idmap);
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 89ff9f5..17d97a2 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -23,7 +23,8 @@
#include <unordered_map>
#include <unordered_set>
-#include "android-base/macros.h"
+#include <android-base/macros.h>
+#include <android-base/result.h>
#include "androidfw/ByteBucketArray.h"
#include "androidfw/Chunk.h"
@@ -49,7 +50,7 @@
// Pointer to the mmapped data where flags are kept.
// Flags denote whether the resource entry is public
// and under which configurations it varies.
- const ResTable_typeSpec* type_spec;
+ incfs::verified_map_ptr<ResTable_typeSpec> type_spec;
// The number of types that follow this struct.
// There is a type for each configuration that entries are defined for.
@@ -57,15 +58,17 @@
// Trick to easily access a variable number of Type structs
// proceeding this struct, and to ensure their alignment.
- const ResTable_type* types[0];
+ incfs::verified_map_ptr<ResTable_type> types[0];
- inline uint32_t GetFlagsForEntryIndex(uint16_t entry_index) const {
+ base::expected<uint32_t, NullOrIOError> GetFlagsForEntryIndex(uint16_t entry_index) const {
if (entry_index >= dtohl(type_spec->entryCount)) {
- return 0u;
+ return 0U;
}
-
- const uint32_t* flags = reinterpret_cast<const uint32_t*>(type_spec + 1);
- return flags[entry_index];
+ const auto entry_flags_ptr = ((type_spec + 1).convert<uint32_t>() + entry_index);
+ if (!entry_flags_ptr) {
+ return base::unexpected(IOError::PAGES_MISSING);
+ }
+ return entry_flags_ptr.value();
}
};
@@ -161,13 +164,17 @@
// the default policy in AAPT2 is to build UTF-8 string pools, this needs to change.
// Returns a partial resource ID, with the package ID left as 0x00. The caller is responsible
// for patching the correct package ID to the resource ID.
- uint32_t FindEntryByName(const std::u16string& type_name, const std::u16string& entry_name) const;
+ base::expected<uint32_t, NullOrIOError> FindEntryByName(const std::u16string& type_name,
+ const std::u16string& entry_name) const;
- static const ResTable_entry* GetEntry(const ResTable_type* type_chunk, uint16_t entry_index);
+ static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntry(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
- static uint32_t GetEntryOffset(const ResTable_type* type_chunk, uint16_t entry_index);
+ static base::expected<uint32_t, NullOrIOError> GetEntryOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint16_t entry_index);
- static const ResTable_entry* GetEntryFromOffset(const ResTable_type* type_chunk, uint32_t offset);
+ static base::expected<incfs::map_ptr<ResTable_entry>, NullOrIOError> GetEntryFromOffset(
+ incfs::verified_map_ptr<ResTable_type> type_chunk, uint32_t offset);
// Returns the string pool where type names are stored.
inline const ResStringPool* GetTypeStringPool() const {
@@ -220,7 +227,8 @@
// Populates a set of ResTable_config structs, possibly excluding configurations defined for
// the mipmap type.
- void CollectConfigurations(bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
+ base::expected<std::monostate, IOError> CollectConfigurations(
+ bool exclude_mipmap, std::set<ResTable_config>* out_configs) const;
// Populates a set of strings representing locales.
// If `canonicalize` is set to true, each locale is transformed into its canonical format
@@ -300,7 +308,8 @@
// If `load_as_shared_library` is set to true, the application package (0x7f) is treated
// as a shared library (0x00). When loaded into an AssetManager, the package will be assigned an
// ID.
- static std::unique_ptr<const LoadedArsc> Load(const StringPiece& data,
+ static std::unique_ptr<const LoadedArsc> Load(incfs::map_ptr<void> data,
+ size_t length,
const LoadedIdmap* loaded_idmap = nullptr,
package_property_t property_flags = 0U);
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 04ba78b..fb5f864 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -20,7 +20,10 @@
#ifndef _LIBS_UTILS_RESOURCE_TYPES_H
#define _LIBS_UTILS_RESOURCE_TYPES_H
+#include <android-base/expected.h>
+
#include <androidfw/Asset.h>
+#include <androidfw/Errors.h>
#include <androidfw/LocaleData.h>
#include <androidfw/StringPiece.h>
#include <utils/Errors.h>
@@ -497,7 +500,7 @@
virtual ~ResStringPool();
void setToEmpty();
- status_t setTo(const void* data, size_t size, bool copyData=false);
+ status_t setTo(incfs::map_ptr<void> data, size_t size, bool copyData=false);
status_t getError() const;
@@ -505,48 +508,49 @@
// Return string entry as UTF16; if the pool is UTF8, the string will
// be converted before returning.
- inline const char16_t* stringAt(const ResStringPool_ref& ref, size_t* outLen) const {
- return stringAt(ref.index, outLen);
+ inline base::expected<StringPiece16, NullOrIOError> stringAt(
+ const ResStringPool_ref& ref) const {
+ return stringAt(ref.index);
}
- virtual const char16_t* stringAt(size_t idx, size_t* outLen) const;
+ virtual base::expected<StringPiece16, NullOrIOError> stringAt(size_t idx) const;
// Note: returns null if the string pool is not UTF8.
- virtual const char* string8At(size_t idx, size_t* outLen) const;
+ virtual base::expected<StringPiece, NullOrIOError> string8At(size_t idx) const;
// Return string whether the pool is UTF8 or UTF16. Does not allow you
// to distinguish null.
- const String8 string8ObjectAt(size_t idx) const;
+ base::expected<String8, IOError> string8ObjectAt(size_t idx) const;
- const ResStringPool_span* styleAt(const ResStringPool_ref& ref) const;
- const ResStringPool_span* styleAt(size_t idx) const;
+ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt(
+ const ResStringPool_ref& ref) const;
+ base::expected<incfs::map_ptr<ResStringPool_span>, NullOrIOError> styleAt(size_t idx) const;
- ssize_t indexOfString(const char16_t* str, size_t strLen) const;
+ base::expected<size_t, NullOrIOError> indexOfString(const char16_t* str, size_t strLen) const;
virtual size_t size() const;
size_t styleCount() const;
size_t bytes() const;
- const void* data() const;
-
+ incfs::map_ptr<void> data() const;
bool isSorted() const;
bool isUTF8() const;
private:
- status_t mError;
- void* mOwnedData;
- const ResStringPool_header* mHeader;
- size_t mSize;
- mutable Mutex mDecodeLock;
- const uint32_t* mEntries;
- const uint32_t* mEntryStyles;
- const void* mStrings;
- char16_t mutable** mCache;
- uint32_t mStringPoolSize; // number of uint16_t
- const uint32_t* mStyles;
- uint32_t mStylePoolSize; // number of uint32_t
+ status_t mError;
+ void* mOwnedData;
+ incfs::verified_map_ptr<ResStringPool_header> mHeader;
+ size_t mSize;
+ mutable Mutex mDecodeLock;
+ incfs::map_ptr<uint32_t> mEntries;
+ incfs::map_ptr<uint32_t> mEntryStyles;
+ incfs::map_ptr<void> mStrings;
+ char16_t mutable** mCache;
+ uint32_t mStringPoolSize; // number of uint16_t
+ incfs::map_ptr<uint32_t> mStyles;
+ uint32_t mStylePoolSize; // number of uint32_t
- const char* stringDecodeAt(size_t idx, const uint8_t* str, const size_t encLen,
- size_t* outLen) const;
+ base::expected<StringPiece, NullOrIOError> stringDecodeAt(
+ size_t idx, incfs::map_ptr<uint8_t> str, size_t encLen) const;
};
/**
@@ -558,8 +562,8 @@
StringPoolRef() = default;
StringPoolRef(const ResStringPool* pool, uint32_t index);
- const char* string8(size_t* outLen) const;
- const char16_t* string16(size_t* outLen) const;
+ base::expected<StringPiece, NullOrIOError> string8() const;
+ base::expected<StringPiece16, NullOrIOError> string16() const;
private:
const ResStringPool* mPool = nullptr;
@@ -1797,6 +1801,16 @@
bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
+template<typename TChar, typename E>
+static const TChar* UnpackOptionalString(base::expected<BasicStringPiece<TChar>, E>&& result,
+ size_t* outLen) {
+ if (result.has_value()) {
+ *outLen = result->size();
+ return result->data();
+ }
+ return NULL;
+}
+
/**
* Convenience class for accessing data in a ResTable resource.
*/
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index e649940..bd1c440 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -30,13 +30,12 @@
// Convert a type_string_ref, entry_string_ref, and package to AssetManager2::ResourceName.
// Useful for getting resource name without re-running AssetManager2::FindEntry searches.
-bool ToResourceName(const StringPoolRef& type_string_ref,
- const StringPoolRef& entry_string_ref,
- const StringPiece& package_name,
- AssetManager2::ResourceName* out_name);
+base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
+ const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
+ const StringPiece& package_name);
// Formats a ResourceName to "package:type/entry_name".
-std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name);
+std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name);
inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) {
return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24);
diff --git a/libs/androidfw/include/androidfw/StreamingZipInflater.h b/libs/androidfw/include/androidfw/StreamingZipInflater.h
index 3ace5d5..472b794b 100644
--- a/libs/androidfw/include/androidfw/StreamingZipInflater.h
+++ b/libs/androidfw/include/androidfw/StreamingZipInflater.h
@@ -19,6 +19,8 @@
#include <unistd.h>
#include <inttypes.h>
+
+#include <util/map_ptr.h>
#include <zlib.h>
#include <utils/Compat.h>
@@ -34,7 +36,7 @@
StreamingZipInflater(int fd, off64_t compDataStart, size_t uncompSize, size_t compSize);
// Flavor that gets the compressed data from an in-memory buffer
- StreamingZipInflater(class FileMap* dataMap, size_t uncompSize);
+ StreamingZipInflater(const incfs::IncFsFileMap* dataMap, size_t uncompSize);
~StreamingZipInflater();
@@ -54,7 +56,7 @@
// where to find the uncompressed data
int mFd;
off64_t mInFileStart; // where the compressed data lives in the file
- class FileMap* mDataMap;
+ const incfs::IncFsFileMap* mDataMap;
z_stream mInflateState;
bool mStreamNeedsInit;
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 9a3646b..aceeecc 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -22,7 +22,8 @@
#include <sstream>
#include <vector>
-#include "android-base/macros.h"
+#include <android-base/macros.h>
+#include <util/map_ptr.h>
#include "androidfw/StringPiece.h"
@@ -126,6 +127,11 @@
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+template <typename T>
+bool IsFourByteAligned(const incfs::map_ptr<T>& data) {
+ return ((size_t)data.unsafe_ptr() & 0x3U) == 0;
+}
+
} // namespace util
} // namespace android
diff --git a/libs/androidfw/include/androidfw/ZipFileRO.h b/libs/androidfw/include/androidfw/ZipFileRO.h
index c221e3b..10f6d06 100644
--- a/libs/androidfw/include/androidfw/ZipFileRO.h
+++ b/libs/androidfw/include/androidfw/ZipFileRO.h
@@ -30,17 +30,20 @@
#ifndef __LIBS_ZIPFILERO_H
#define __LIBS_ZIPFILERO_H
-#include <utils/Compat.h>
-#include <utils/Errors.h>
-#include <utils/FileMap.h>
-#include <utils/threads.h>
-
+#include <optional>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
+#include <util/map_ptr.h>
+
+#include <utils/Compat.h>
+#include <utils/Errors.h>
+#include <utils/FileMap.h>
+#include <utils/threads.h>
+
struct ZipArchive;
typedef ZipArchive* ZipArchiveHandle;
@@ -136,14 +139,26 @@
uint32_t* pCrc32) const;
/*
- * Create a new FileMap object that maps a subset of the archive. For
+ * Create a new FileMap object that maps a subset of the archive. For
* an uncompressed entry this effectively provides a pointer to the
* actual data, for a compressed entry this provides the input buffer
* for inflate().
+ *
+ * Use this function if the archive can never reside on IncFs.
*/
FileMap* createEntryFileMap(ZipEntryRO entry) const;
/*
+ * Create a new incfs::IncFsFileMap object that maps a subset of the archive. For
+ * an uncompressed entry this effectively provides a pointer to the
+ * actual data, for a compressed entry this provides the input buffer
+ * for inflate().
+ *
+ * Use this function if the archive can potentially reside on IncFs.
+ */
+ std::optional<incfs::IncFsFileMap> createEntryIncFsFileMap(ZipEntryRO entry) const;
+
+ /*
* Uncompress the data into a buffer. Depending on the compression
* format, this is either an "inflate" operation or a memcpy.
*
diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
index 4d35e99..dbfec34 100644
--- a/libs/androidfw/include/androidfw/ZipUtils.h
+++ b/libs/androidfw/include/androidfw/ZipUtils.h
@@ -25,6 +25,8 @@
#include <stdio.h>
#include <time.h>
+#include "util/map_ptr.h"
+
namespace android {
/*
@@ -40,8 +42,8 @@
long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen,
- long compressedLen);
+ static bool inflateToBuffer(incfs::map_ptr<void> in, void* buf,
+ long uncompressedLen, long compressedLen);
/*
* Someday we might want to make this generic and handle bzip2 ".bz2"
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
index 437e147..c7ae618 100644
--- a/libs/androidfw/tests/AssetManager2_bench.cpp
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -139,9 +139,13 @@
assets.SetApkAssets({apk.get()});
while (state.KeepRunning()) {
- const ResolvedBag* bag = assets.GetBag(app::R::style::StyleTwo);
- const auto bag_end = end(bag);
- for (auto iter = begin(bag); iter != bag_end; ++iter) {
+ auto bag = assets.GetBag(app::R::style::StyleTwo);
+ if (!bag.has_value()) {
+ state.SkipWithError("Failed to load get bag");
+ return;
+ }
+ const auto bag_end = end(*bag);
+ for (auto iter = begin(*bag); iter != bag_end; ++iter) {
uint32_t key = iter->key;
Res_value value = iter->value;
benchmark::DoNotOptimize(key);
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 8c255d1..471b0ee 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -108,24 +108,18 @@
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
// Came from our ApkAssets.
- EXPECT_EQ(0, cookie);
+ EXPECT_EQ(0, value->cookie);
// It is the default config.
- EXPECT_EQ(0, selected_config.language[0]);
- EXPECT_EQ(0, selected_config.language[1]);
+ EXPECT_EQ(0, value->config.language[0]);
+ EXPECT_EQ(0, value->config.language[1]);
// It is a string.
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
}
TEST_F(AssetManager2Test, FindsResourceFromMultipleApkAssets) {
@@ -138,24 +132,18 @@
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
// Came from our de_fr ApkAssets.
- EXPECT_EQ(1, cookie);
+ EXPECT_EQ(1, value->cookie);
// The configuration is German.
- EXPECT_EQ('d', selected_config.language[0]);
- EXPECT_EQ('e', selected_config.language[1]);
+ EXPECT_EQ('d', value->config.language[0]);
+ EXPECT_EQ('e', value->config.language[1]);
// It is a string.
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
}
TEST_F(AssetManager2Test, FindsResourceFromSharedLibrary) {
@@ -166,44 +154,35 @@
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(libclient::R::string::foo_one, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(libclient::R::string::foo_one);
+ ASSERT_TRUE(value.has_value());
// Reference comes from libclient.
- EXPECT_EQ(2, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ EXPECT_EQ(2, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// Lookup the reference.
- cookie = assetmanager.GetResource(value.data, false /* may_be_bag */, 0 /* density_override*/,
- &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(1, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ value = assetmanager.GetResource(value->data);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
EXPECT_EQ(std::string("Foo from lib_one"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(cookie), value.data));
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie), value->data));
- cookie = assetmanager.GetResource(libclient::R::string::foo_two, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ value = assetmanager.GetResource(libclient::R::string::foo_two);
+ ASSERT_TRUE(value.has_value());
// Reference comes from libclient.
- EXPECT_EQ(2, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ EXPECT_EQ(2, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// Lookup the reference.
- cookie = assetmanager.GetResource(value.data, false /* may_be_bag */, 0 /* density_override*/,
- &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(0, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+ value = assetmanager.GetResource(value->data);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
EXPECT_EQ(std::string("Foo from lib_two"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(cookie), value.data));
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(value->cookie), value->data));
}
TEST_F(AssetManager2Test, FindsResourceFromAppLoadedAsSharedLibrary) {
@@ -211,16 +190,10 @@
assetmanager.SetApkAssets({appaslib_assets_.get()});
// The appaslib package will have been assigned the package ID 0x02.
-
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie = assetmanager.GetResource(
- fix_package_id(appaslib::R::integer::number1, 0x02), false /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value.data);
+ auto value = assetmanager.GetResource(fix_package_id(appaslib::R::integer::number1, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(fix_package_id(appaslib::R::array::integerArray1, 0x02), value->data);
}
TEST_F(AssetManager2Test, AssignsOverlayPackageIdLast) {
@@ -238,40 +211,40 @@
return assetmanager.GetAssignedPackageId(apkAssets->GetLoadedArsc()->GetPackages()[0].get());
};
- ASSERT_EQ(get_first_package_id(overlayable_assets_.get()), 0x7f);
- ASSERT_EQ(get_first_package_id(overlay_assets_.get()), 0x03);
- ASSERT_EQ(get_first_package_id(lib_one_assets_.get()), 0x02);
+ ASSERT_EQ(0x7f, get_first_package_id(overlayable_assets_.get()));
+ ASSERT_EQ(0x03, get_first_package_id(overlay_assets_.get()));
+ ASSERT_EQ(0x02, get_first_package_id(lib_one_assets_.get()));
}
TEST_F(AssetManager2Test, GetSharedLibraryResourceName) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({lib_one_assets_.get()});
- AssetManager2::ResourceName name;
- ASSERT_TRUE(assetmanager.GetResourceName(lib_one::R::string::foo, &name));
- std::string formatted_name = ToFormattedResourceString(&name);
- ASSERT_EQ(formatted_name, "com.android.lib_one:string/foo");
+ auto name = assetmanager.GetResourceName(lib_one::R::string::foo);
+ ASSERT_TRUE(name.has_value());
+ ASSERT_EQ("com.android.lib_one:string/foo", ToFormattedResourceString(*name));
}
TEST_F(AssetManager2Test, FindsBagResourceFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(basic::R::array::integerArray1);
- ASSERT_NE(nullptr, bag);
- ASSERT_EQ(3u, bag->entry_count);
+ auto bag = assetmanager.GetBag(basic::R::array::integerArray1);
+ ASSERT_TRUE(bag.has_value());
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[0].value.dataType);
- EXPECT_EQ(1u, bag->entries[0].value.data);
- EXPECT_EQ(0, bag->entries[0].cookie);
+ ASSERT_EQ(3u, (*bag)->entry_count);
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[1].value.dataType);
- EXPECT_EQ(2u, bag->entries[1].value.data);
- EXPECT_EQ(0, bag->entries[1].cookie);
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag)->entries[0].cookie);
- EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[2].value.dataType);
- EXPECT_EQ(3u, bag->entries[2].value.data);
- EXPECT_EQ(0, bag->entries[2].cookie);
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[1].value.dataType);
+ EXPECT_EQ(2u, (*bag)->entries[1].value.data);
+ EXPECT_EQ(0, (*bag)->entries[1].cookie);
+
+ EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), (*bag)->entries[2].value.dataType);
+ EXPECT_EQ(3u, (*bag)->entries[2].value.data);
+ EXPECT_EQ(0, (*bag)->entries[2].cookie);
}
TEST_F(AssetManager2Test, FindsBagResourceFromMultipleApkAssets) {}
@@ -284,15 +257,16 @@
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
- ASSERT_NE(nullptr, bag);
- ASSERT_GE(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(fix_package_id(lib_one::R::style::Theme, 0x03));
+ ASSERT_TRUE(bag.has_value());
+
+ ASSERT_GE((*bag)->entry_count, 2u);
// First two attributes come from lib_one.
- EXPECT_EQ(1, bag->entries[0].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
- EXPECT_EQ(1, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(1, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[0].key));
+ EXPECT_EQ(1, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, FindsBagResourceFromMultipleSharedLibraries) {
@@ -303,17 +277,17 @@
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib);
- ASSERT_NE(nullptr, bag);
- ASSERT_EQ(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(libclient::R::style::ThemeMultiLib);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_EQ((*bag)->entry_count, 2u);
// First attribute comes from lib_two.
- EXPECT_EQ(2, bag->entries[0].cookie);
- EXPECT_EQ(0x02, get_package_id(bag->entries[0].key));
+ EXPECT_EQ(2, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x02, get_package_id((*bag)->entries[0].key));
// The next two attributes come from lib_one.
- EXPECT_EQ(2, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(2, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, FindsStyleResourceWithParentFromSharedLibrary) {
@@ -324,79 +298,79 @@
assetmanager.SetApkAssets(
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
- const ResolvedBag* bag = assetmanager.GetBag(libclient::R::style::Theme);
- ASSERT_NE(nullptr, bag);
- ASSERT_GE(bag->entry_count, 2u);
+ auto bag = assetmanager.GetBag(libclient::R::style::Theme);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_GE((*bag)->entry_count, 2u);
// First two attributes come from lib_one.
- EXPECT_EQ(1, bag->entries[0].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[0].key));
- EXPECT_EQ(1, bag->entries[1].cookie);
- EXPECT_EQ(0x03, get_package_id(bag->entries[1].key));
+ EXPECT_EQ(1, (*bag)->entries[0].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[0].key));
+ EXPECT_EQ(1, (*bag)->entries[1].cookie);
+ EXPECT_EQ(0x03, get_package_id((*bag)->entries[1].key));
}
TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({style_assets_.get()});
- const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleOne);
- ASSERT_NE(nullptr, bag_one);
- ASSERT_EQ(2u, bag_one->entry_count);
+ auto bag_one = assetmanager.GetBag(app::R::style::StyleOne);
+ ASSERT_TRUE(bag_one.has_value());
+ ASSERT_EQ(2u, (*bag_one)->entry_count);
- EXPECT_EQ(app::R::attr::attr_one, bag_one->entries[0].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[0].value.dataType);
- EXPECT_EQ(1u, bag_one->entries[0].value.data);
- EXPECT_EQ(0, bag_one->entries[0].cookie);
+ EXPECT_EQ(app::R::attr::attr_one, (*bag_one)->entries[0].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_one)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag_one)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag_one)->entries[0].cookie);
- EXPECT_EQ(app::R::attr::attr_two, bag_one->entries[1].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[1].value.dataType);
- EXPECT_EQ(2u, bag_one->entries[1].value.data);
- EXPECT_EQ(0, bag_one->entries[1].cookie);
+ EXPECT_EQ(app::R::attr::attr_two, (*bag_one)->entries[1].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_one)->entries[1].value.dataType);
+ EXPECT_EQ(2u, (*bag_one)->entries[1].value.data);
+ EXPECT_EQ(0, (*bag_one)->entries[1].cookie);
- const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
- ASSERT_NE(nullptr, bag_two);
- ASSERT_EQ(6u, bag_two->entry_count);
+ auto bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
+ ASSERT_TRUE(bag_two.has_value());
+ ASSERT_EQ(6u, (*bag_two)->entry_count);
// attr_one is inherited from StyleOne.
- EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[0].value.dataType);
- EXPECT_EQ(1u, bag_two->entries[0].value.data);
- EXPECT_EQ(0, bag_two->entries[0].cookie);
- EXPECT_EQ(app::R::style::StyleOne, bag_two->entries[0].style);
+ EXPECT_EQ(app::R::attr::attr_one, (*bag_two)->entries[0].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_two)->entries[0].value.dataType);
+ EXPECT_EQ(1u, (*bag_two)->entries[0].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[0].cookie);
+ EXPECT_EQ(app::R::style::StyleOne, (*bag_two)->entries[0].style);
// attr_two should be overridden from StyleOne by StyleTwo.
- EXPECT_EQ(app::R::attr::attr_two, bag_two->entries[1].key);
- EXPECT_EQ(Res_value::TYPE_STRING, bag_two->entries[1].value.dataType);
- EXPECT_EQ(0, bag_two->entries[1].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[1].style);
+ EXPECT_EQ(app::R::attr::attr_two, (*bag_two)->entries[1].key);
+ EXPECT_EQ(Res_value::TYPE_STRING, (*bag_two)->entries[1].value.dataType);
+ EXPECT_EQ(0, (*bag_two)->entries[1].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[1].style);
EXPECT_EQ(std::string("string"), GetStringFromPool(assetmanager.GetStringPoolForCookie(0),
- bag_two->entries[1].value.data));
+ (*bag_two)->entries[1].value.data));
// The rest are new attributes.
- EXPECT_EQ(app::R::attr::attr_three, bag_two->entries[2].key);
- EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, bag_two->entries[2].value.dataType);
- EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[2].value.data);
- EXPECT_EQ(0, bag_two->entries[2].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[2].style);
+ EXPECT_EQ(app::R::attr::attr_three, (*bag_two)->entries[2].key);
+ EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, (*bag_two)->entries[2].value.dataType);
+ EXPECT_EQ(app::R::attr::attr_indirect, (*bag_two)->entries[2].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[2].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[2].style);
- EXPECT_EQ(app::R::attr::attr_five, bag_two->entries[3].key);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, bag_two->entries[3].value.dataType);
- EXPECT_EQ(app::R::string::string_one, bag_two->entries[3].value.data);
- EXPECT_EQ(0, bag_two->entries[3].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[3].style);
+ EXPECT_EQ(app::R::attr::attr_five, (*bag_two)->entries[3].key);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, (*bag_two)->entries[3].value.dataType);
+ EXPECT_EQ(app::R::string::string_one, (*bag_two)->entries[3].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[3].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[3].style);
- EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[4].key);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
- EXPECT_EQ(3u, bag_two->entries[4].value.data);
- EXPECT_EQ(0, bag_two->entries[4].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[4].style);
+ EXPECT_EQ(app::R::attr::attr_indirect, (*bag_two)->entries[4].key);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, (*bag_two)->entries[4].value.dataType);
+ EXPECT_EQ(3u, (*bag_two)->entries[4].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[4].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[4].style);
- EXPECT_EQ(app::R::attr::attr_empty, bag_two->entries[5].key);
- EXPECT_EQ(Res_value::TYPE_NULL, bag_two->entries[5].value.dataType);
- EXPECT_EQ(Res_value::DATA_NULL_EMPTY, bag_two->entries[5].value.data);
- EXPECT_EQ(0, bag_two->entries[5].cookie);
- EXPECT_EQ(app::R::style::StyleTwo, bag_two->entries[5].style);
+ EXPECT_EQ(app::R::attr::attr_empty, (*bag_two)->entries[5].key);
+ EXPECT_EQ(Res_value::TYPE_NULL, (*bag_two)->entries[5].value.dataType);
+ EXPECT_EQ(Res_value::DATA_NULL_EMPTY, (*bag_two)->entries[5].value.data);
+ EXPECT_EQ(0, (*bag_two)->entries[5].cookie);
+ EXPECT_EQ(app::R::style::StyleTwo, (*bag_two)->entries[5].style);
}
TEST_F(AssetManager2Test, MergeStylesCircularDependency) {
@@ -405,55 +379,41 @@
// GetBag should stop traversing the parents of styles when a circular
// dependency is detected
- const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleFour);
- ASSERT_NE(nullptr, bag_one);
- ASSERT_EQ(3u, bag_one->entry_count);
+ auto bag = assetmanager.GetBag(app::R::style::StyleFour);
+ ASSERT_TRUE(bag.has_value());
+ ASSERT_EQ(3u, (*bag)->entry_count);
}
TEST_F(AssetManager2Test, ResolveReferenceToResource) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::integer::ref1, false /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::integer::ref1);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::integer::ref2, value->data);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::integer::ref2, value.data);
-
- uint32_t last_ref = 0u;
- cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(12000u, value.data);
- EXPECT_EQ(basic::R::integer::ref2, last_ref);
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(12000u, value->data);
+ EXPECT_EQ(basic::R::integer::ref2, value->resid);
}
TEST_F(AssetManager2Test, ResolveReferenceToBag) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/,
- 0u /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::integer::number2, true /*may_be_bag*/);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::array::integerArray1, value->data);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::array::integerArray1, value.data);
-
- uint32_t last_ref = 0u;
- cookie = assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_ref);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(basic::R::array::integerArray1, value.data);
- EXPECT_EQ(basic::R::array::integerArray1, last_ref);
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(basic::R::array::integerArray1, value->data);
+ EXPECT_EQ(basic::R::array::integerArray1, value->resid);
}
TEST_F(AssetManager2Test, ResolveDeepIdReference) {
@@ -461,50 +421,107 @@
assetmanager.SetApkAssets({basic_assets_.get()});
// Set up the resource ids
- const uint32_t high_ref = assetmanager
- .GetResourceId("@id/high_ref", "values", "com.android.basic");
- ASSERT_NE(high_ref, 0u);
- const uint32_t middle_ref = assetmanager
- .GetResourceId("@id/middle_ref", "values", "com.android.basic");
- ASSERT_NE(middle_ref, 0u);
- const uint32_t low_ref = assetmanager
- .GetResourceId("@id/low_ref", "values", "com.android.basic");
- ASSERT_NE(low_ref, 0u);
+ auto high_ref = assetmanager.GetResourceId("@id/high_ref", "values", "com.android.basic");
+ ASSERT_TRUE(high_ref.has_value());
+
+ auto middle_ref = assetmanager.GetResourceId("@id/middle_ref", "values", "com.android.basic");
+ ASSERT_TRUE(middle_ref.has_value());
+
+ auto low_ref = assetmanager.GetResourceId("@id/low_ref", "values", "com.android.basic");
+ ASSERT_TRUE(low_ref.has_value());
// Retrieve the most shallow resource
- Res_value value;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = assetmanager.GetResource(high_ref, false /*may_be_bag*/,
- 0 /*density_override*/,
- &value, &config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(middle_ref, value.data);
+ auto value = assetmanager.GetResource(*high_ref);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(*middle_ref, value->data);;
// Check that resolving the reference resolves to the deepest id
- uint32_t last_ref = high_ref;
- assetmanager.ResolveReference(cookie, &value, &config, &flags, &last_ref);
- EXPECT_EQ(last_ref, low_ref);
+ auto result = assetmanager.ResolveReference(*value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(*low_ref, value->resid);
}
TEST_F(AssetManager2Test, KeepLastReferenceIdUnmodifiedIfNoReferenceIsResolved) {
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- ResTable_config selected_config;
- memset(&selected_config, 0, sizeof(selected_config));
+ // Create some kind of value that is NOT a reference.
+ AssetManager2::SelectedValue value{};
+ value.cookie = 1;
+ value.type = Res_value::TYPE_STRING;
+ value.resid = basic::R::string::test1;
- uint32_t flags = 0u;
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(1, value.cookie);
+ EXPECT_EQ(basic::R::string::test1, value.resid);
+}
- // Create some kind of Res_value that is NOT a reference.
- Res_value value;
- value.dataType = Res_value::TYPE_STRING;
- value.data = 0;
+TEST_F(AssetManager2Test, ResolveReferenceMissingResourceDoNotCacheFlags) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_assets_.get()});
+ {
+ AssetManager2::SelectedValue value{};
+ value.data = basic::R::string::test1;
+ value.type = Res_value::TYPE_REFERENCE;
+ value.flags = ResTable_config::CONFIG_KEYBOARD;
- uint32_t last_ref = basic::R::string::test1;
- EXPECT_EQ(1, assetmanager.ResolveReference(1, &value, &selected_config, &flags, &last_ref));
- EXPECT_EQ(basic::R::string::test1, last_ref);
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_STRING, value.type);
+ EXPECT_EQ(0, value.cookie);
+ EXPECT_EQ(basic::R::string::test1, value.resid);
+ EXPECT_EQ(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_KEYBOARD, value.flags);
+ }
+ {
+ AssetManager2::SelectedValue value{};
+ value.data = basic::R::string::test1;
+ value.type = Res_value::TYPE_REFERENCE;
+ value.flags = ResTable_config::CONFIG_COLOR_MODE;
+
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_STRING, value.type);
+ EXPECT_EQ(0, value.cookie);
+ EXPECT_EQ(basic::R::string::test1, value.resid);
+ EXPECT_EQ(ResTable_typeSpec::SPEC_PUBLIC | ResTable_config::CONFIG_COLOR_MODE, value.flags);
+ }
+}
+
+TEST_F(AssetManager2Test, ResolveReferenceMissingResource) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({basic_assets_.get()});
+
+ const uint32_t kMissingResId = 0x8001ffff;
+ AssetManager2::SelectedValue value{};
+ value.type = Res_value::TYPE_REFERENCE;
+ value.data = kMissingResId;
+
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_FALSE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value.type);
+ EXPECT_EQ(kMissingResId, value.data);
+ EXPECT_EQ(kMissingResId, value.resid);
+ EXPECT_EQ(-1, value.cookie);
+ EXPECT_EQ(0, value.flags);
+}
+
+TEST_F(AssetManager2Test, ResolveReferenceMissingResourceLib) {
+ AssetManager2 assetmanager;
+ assetmanager.SetApkAssets({libclient_assets_.get()});
+
+ AssetManager2::SelectedValue value{};
+ value.type = Res_value::TYPE_REFERENCE;
+ value.data = libclient::R::string::foo_one;
+
+ auto result = assetmanager.ResolveReference(value);
+ ASSERT_TRUE(result.has_value());
+ EXPECT_EQ(Res_value::TYPE_DYNAMIC_REFERENCE, value.type);
+ EXPECT_EQ(lib_one::R::string::foo, value.data);
+ EXPECT_EQ(libclient::R::string::foo_one, value.resid);
+ EXPECT_EQ(0, value.cookie);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value.flags);
}
static bool IsConfigurationPresent(const std::set<ResTable_config>& configurations,
@@ -516,43 +533,45 @@
AssetManager2 assetmanager;
assetmanager.SetApkAssets({system_assets_.get(), basic_de_fr_assets_.get()});
- std::set<ResTable_config> configurations = assetmanager.GetResourceConfigurations();
+ auto configurations = assetmanager.GetResourceConfigurations();
+ ASSERT_TRUE(configurations.has_value());
// We expect the locale sv from the system assets, and de and fr from basic_de_fr assets.
// And one extra for the default configuration.
- EXPECT_EQ(4u, configurations.size());
+ EXPECT_EQ(4u, configurations->size());
ResTable_config expected_config;
memset(&expected_config, 0, sizeof(expected_config));
expected_config.language[0] = 's';
expected_config.language[1] = 'v';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'd';
expected_config.language[1] = 'e';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'f';
expected_config.language[1] = 'r';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
// Take out the system assets.
configurations = assetmanager.GetResourceConfigurations(true /* exclude_system */);
+ ASSERT_TRUE(configurations.has_value());
// We expect de and fr from basic_de_fr assets.
- EXPECT_EQ(2u, configurations.size());
+ EXPECT_EQ(2u, configurations->size());
expected_config.language[0] = 's';
expected_config.language[1] = 'v';
- EXPECT_FALSE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_FALSE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'd';
expected_config.language[1] = 'e';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
expected_config.language[0] = 'f';
expected_config.language[1] = 'r';
- EXPECT_TRUE(IsConfigurationPresent(configurations, expected_config));
+ EXPECT_TRUE(IsConfigurationPresent(*configurations, expected_config));
}
TEST_F(AssetManager2Test, GetResourceLocales) {
@@ -578,12 +597,17 @@
AssetManager2 assetmanager;
assetmanager.SetApkAssets({basic_assets_.get()});
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("com.android.basic:layout/main", "", ""));
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("layout/main", "", "com.android.basic"));
- EXPECT_EQ(basic::R::layout::main,
- assetmanager.GetResourceId("main", "layout", "com.android.basic"));
+ auto resid = assetmanager.GetResourceId("com.android.basic:layout/main", "", "");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
+
+ resid = assetmanager.GetResourceId("layout/main", "", "com.android.basic");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
+
+ resid = assetmanager.GetResourceId("main", "layout", "com.android.basic");
+ ASSERT_TRUE(resid.has_value());
+ EXPECT_EQ(basic::R::layout::main, *resid);
}
TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {
@@ -658,14 +682,8 @@
assetmanager.SetApkAssets({basic_assets_.get()});
assetmanager.SetResourceResolutionLoggingEnabled(false);
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
EXPECT_EQ("", result);
@@ -693,17 +711,12 @@
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result);
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config -de\n\tFound initial: com.android.basic", result);
}
TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) {
@@ -717,17 +730,14 @@
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
- Res_value value = Res_value();
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto result = assetmanager.GetLastResourceResolution();
- EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result);
+ EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n"
+ "\tFor config -de\n"
+ "\tFound initial: com.android.basic\n"
+ "\tFound better: com.android.basic -de", result);
}
TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) {
@@ -739,14 +749,8 @@
assetmanager.SetConfiguration(desired_config);
assetmanager.SetApkAssets({basic_assets_.get()});
- Res_value value = Res_value();
- ResTable_config selected_config;
- uint32_t flags;
-
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
- 0 /*density_override*/, &value, &selected_config, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
+ auto value = assetmanager.GetResource(basic::R::string::test1);
+ ASSERT_TRUE(value.has_value());
auto resultEnabled = assetmanager.GetLastResourceResolution();
ASSERT_NE("", resultEnabled);
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
index fa300c5..ddd8ab8 100644
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ b/libs/androidfw/tests/AttributeResolution_bench.cpp
@@ -108,27 +108,20 @@
device_config.screenHeightDp = 1024;
device_config.sdkVersion = 27;
- Res_value value;
- ResTable_config config;
- uint32_t flags = 0u;
- ApkAssetsCookie cookie =
- assetmanager.GetResource(basic::R::layout::layoutt, false /*may_be_bag*/,
- 0u /*density_override*/, &value, &config, &flags);
- if (cookie == kInvalidCookie) {
+ auto value = assetmanager.GetResource(basic::R::layout::layoutt);
+ if (!value.has_value()) {
state.SkipWithError("failed to find R.layout.layout");
return;
}
- size_t len = 0u;
- const char* layout_path =
- assetmanager.GetStringPoolForCookie(cookie)->string8At(value.data, &len);
- if (layout_path == nullptr || len == 0u) {
+ auto layout_path = assetmanager.GetStringPoolForCookie(value->cookie)->string8At(value->data);
+ if (!layout_path.has_value()) {
state.SkipWithError("failed to lookup layout path");
return;
}
- std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(
- StringPiece(layout_path, len).to_string(), cookie, Asset::ACCESS_BUFFER);
+ std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(layout_path->to_string(), value->cookie,
+ Asset::ACCESS_BUFFER);
if (asset == nullptr) {
state.SkipWithError("failed to load layout");
return;
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 24361b5..bb9129a 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -77,9 +77,9 @@
{fix_package_id(R::attr::attr_one, 0x02), fix_package_id(R::attr::attr_two, 0x02)}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
- fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(), values.data(),
- indices.data());
+ ASSERT_TRUE(ApplyStyle(theme.get(), nullptr /*xml_parser*/, 0u /*def_style_attr*/,
+ fix_package_id(R::style::StyleOne, 0x02), attrs.data(), attrs.size(),
+ values.data(), indices.data()).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -102,7 +102,7 @@
TEST_F(AttributeResolutionTest, Theme) {
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo).has_value());
std::array<uint32_t, 5> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_empty}};
@@ -110,7 +110,7 @@
ASSERT_TRUE(ResolveAttrs(theme.get(), 0u /*def_style_attr*/, 0u /*def_style_res*/,
nullptr /*src_values*/, 0 /*src_values_length*/, attrs.data(),
- attrs.size(), values.data(), nullptr /*out_indices*/));
+ attrs.size(), values.data(), nullptr /*out_indices*/).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
@@ -162,7 +162,7 @@
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
ASSERT_TRUE(RetrieveAttributes(&assetmanager_, &xml_parser_, attrs.data(), attrs.size(),
- values.data(), nullptr /*out_indices*/));
+ values.data(), nullptr /*out_indices*/).has_value());
uint32_t* values_cursor = values.data();
EXPECT_EQ(Res_value::TYPE_NULL, values_cursor[STYLE_TYPE]);
@@ -207,15 +207,15 @@
TEST_F(AttributeResolutionXmlTest, ThemeAndXmlParser) {
std::unique_ptr<Theme> theme = assetmanager_.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo));
+ ASSERT_TRUE(theme->ApplyStyle(R::style::StyleTwo).has_value());
std::array<uint32_t, 6> attrs{{R::attr::attr_one, R::attr::attr_two, R::attr::attr_three,
R::attr::attr_four, R::attr::attr_five, R::attr::attr_empty}};
std::array<uint32_t, attrs.size() * STYLE_NUM_ENTRIES> values;
std::array<uint32_t, attrs.size() + 1> indices;
- ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/, attrs.data(),
- attrs.size(), values.data(), indices.data());
+ ASSERT_TRUE(ApplyStyle(theme.get(), &xml_parser_, 0u /*def_style_attr*/, 0u /*def_style_res*/,
+ attrs.data(), attrs.size(), values.data(), indices.data()).has_value());
const uint32_t public_flag = ResTable_typeSpec::SPEC_PUBLIC;
diff --git a/libs/androidfw/tests/BenchmarkHelpers.cpp b/libs/androidfw/tests/BenchmarkHelpers.cpp
index faddfe5..0fa0573 100644
--- a/libs/androidfw/tests/BenchmarkHelpers.cpp
+++ b/libs/androidfw/tests/BenchmarkHelpers.cpp
@@ -71,15 +71,9 @@
assetmanager.SetConfiguration(*config);
}
- Res_value value;
- ResTable_config selected_config;
- uint32_t flags;
- uint32_t last_id = 0u;
-
while (state.KeepRunning()) {
- ApkAssetsCookie cookie = assetmanager.GetResource(
- resid, false /* may_be_bag */, 0u /* density_override */, &value, &selected_config, &flags);
- assetmanager.ResolveReference(cookie, &value, &selected_config, &flags, &last_id);
+ auto value = assetmanager.GetResource(resid);
+ assetmanager.ResolveReference(*value);
}
}
diff --git a/libs/androidfw/tests/CommonHelpers.cpp b/libs/androidfw/tests/CommonHelpers.cpp
index faa5350..3396729 100644
--- a/libs/androidfw/tests/CommonHelpers.cpp
+++ b/libs/androidfw/tests/CommonHelpers.cpp
@@ -58,8 +58,9 @@
}
std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
- String8 str = pool->string8ObjectAt(idx);
- return std::string(str.string(), str.length());
+ auto str = pool->string8ObjectAt(idx);
+ CHECK(str.has_value()) << "failed to find string entry";
+ return std::string(str->string(), str->length());
}
} // namespace android
diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp
index 7aa0dbb..3f0c7cb 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -62,10 +62,10 @@
std::unique_ptr<const ApkAssets> overlayable_assets_;
};
-std::string GetStringFromApkAssets(const AssetManager2& asset_manager, const Res_value& value,
- ApkAssetsCookie cookie) {
+std::string GetStringFromApkAssets(const AssetManager2& asset_manager,
+ const AssetManager2::SelectedValue& value) {
auto assets = asset_manager.GetApkAssets();
- const ResStringPool* string_pool = assets[cookie]->GetLoadedArsc()->GetStringPool();
+ const ResStringPool* string_pool = assets[value.cookie]->GetLoadedArsc()->GetStringPool();
return GetStringFromPool(string_pool, value.data);
}
@@ -75,117 +75,88 @@
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable5,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "Overlay One");
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable5);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("Overlay One", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingDifferentPackage) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable10,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 0U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "yes");
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable10);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 0U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("yes", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInternalResource) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable8,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_REFERENCE);
- ASSERT_EQ(val.data, (overlay::R::string::internal & 0x00ffffff) | (0x02 << 24));
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable8);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
+ ASSERT_EQ(value->data, (overlay::R::string::internal & 0x00ffffffU) | (0x02U << 24));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineInteger) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::integer::config_integer,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_INT_DEC);
- ASSERT_EQ(val.data, 42);
+
+ auto value = asset_manager.GetResource(overlayable::R::integer::config_integer);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_INT_DEC);
+ ASSERT_EQ(value->data, 42);
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingInlineString) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable11,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "Hardcoded string");
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("Hardcoded string", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayOverridesResourceValueUsingOverlayingResource) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable9,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_REFERENCE);
- ASSERT_EQ(val.data, overlayable::R::string::overlayable7);
+
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable9);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_REFERENCE);
+ ASSERT_EQ(value->data, overlayable::R::string::overlayable7);
}
TEST_F(IdmapTest, OverlayOverridesXmlParser) {
AssetManager2 asset_manager;
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::layout::hello_view,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- ASSERT_EQ(cookie, 2U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "res/layout/hello_view.xml");
- auto asset = asset_manager.OpenNonAsset("res/layout/hello_view.xml", cookie,
+ auto value = asset_manager.GetResource(overlayable::R::layout::hello_view);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(value->cookie, 2U);
+ ASSERT_EQ(value->type, Res_value::TYPE_STRING);
+ ASSERT_EQ("res/layout/hello_view.xml", GetStringFromApkAssets(asset_manager, *value));
+
+ auto asset = asset_manager.OpenNonAsset("res/layout/hello_view.xml", value->cookie,
Asset::ACCESS_RANDOM);
- auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(cookie);
+ auto dynamic_ref_table = asset_manager.GetDynamicRefTableForCookie(value->cookie);
auto xml_tree = util::make_unique<ResXMLTree>(std::move(dynamic_ref_table));
status_t err = xml_tree->setTo(asset->getBuffer(true), asset->getLength(), false);
ASSERT_EQ(err, NO_ERROR);
@@ -216,32 +187,24 @@
asset_manager.SetApkAssets({system_assets_.get(), overlayable_assets_.get(),
overlay_assets_.get()});
- AssetManager2::ResourceName name;
- ASSERT_TRUE(asset_manager.GetResourceName(overlayable::R::string::overlayable9, &name));
- ASSERT_EQ(std::string(name.package), "com.android.overlayable");
- ASSERT_EQ(String16(name.type16), u"string");
- ASSERT_EQ(std::string(name.entry), "overlayable9");
+ auto name = asset_manager.GetResourceName(overlayable::R::string::overlayable9);
+ ASSERT_TRUE(name.has_value());
+ ASSERT_EQ("com.android.overlayable", std::string(name->package));
+ ASSERT_EQ(std::u16string(u"string"), std::u16string(name->type16));
+ ASSERT_EQ("overlayable9", std::string(name->entry));
}
TEST_F(IdmapTest, OverlayLoaderInterop) {
- std::string contents;
auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER);
-
AssetManager2 asset_manager;
asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(),
overlay_assets_.get()});
- Res_value val;
- ResTable_config config;
- uint32_t flags;
- ApkAssetsCookie cookie = asset_manager.GetResource(overlayable::R::string::overlayable11,
- false /* may_be_bag */,
- 0 /* density_override */, &val, &config,
- &flags);
- std::cout << asset_manager.GetLastResourceResolution();
- ASSERT_EQ(cookie, 1U);
- ASSERT_EQ(val.dataType, Res_value::TYPE_STRING);
- ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader");
+ auto value = asset_manager.GetResource(overlayable::R::string::overlayable11);
+ ASSERT_TRUE(value.has_value());
+ ASSERT_EQ(1U, value->cookie);
+ ASSERT_EQ(Res_value::TYPE_STRING, value->type);
+ ASSERT_EQ("loader", GetStringFromApkAssets(asset_manager, *value));
}
TEST_F(IdmapTest, OverlayAssetsIsUpToDate) {
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 2d69dfe..6357411 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -50,7 +50,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ auto loaded_arsc = LoadedArsc::Load(reinterpret_cast<const void*>(contents.data()),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -66,9 +67,8 @@
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
TEST(LoadedArscTest, LoadSparseEntryApp) {
@@ -76,7 +76,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/sparse/sparse.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -90,9 +91,8 @@
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
TEST(LoadedArscTest, LoadSharedLibrary) {
@@ -100,7 +100,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/lib_one/lib_one.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -120,7 +121,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/libclient/libclient.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -145,8 +147,10 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/appaslib/appaslib.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(StringPiece(contents), nullptr /* loaded_idmap */, PROPERTY_DYNAMIC);
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length(),
+ nullptr /* loaded_idmap */,
+ PROPERTY_DYNAMIC);
ASSERT_THAT(loaded_arsc, NotNull());
const auto& packages = loaded_arsc->GetPackages();
@@ -159,7 +163,8 @@
std::string contents;
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/feature/feature.apk", "resources.arsc",
&contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -172,15 +177,12 @@
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(type_index);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
- size_t len;
- const char16_t* type_name16 =
- package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1, &len);
- ASSERT_THAT(type_name16, NotNull());
- EXPECT_THAT(util::Utf16ToUtf8(StringPiece16(type_name16, len)), StrEq("string"));
+ auto type_name16 = package->GetTypeStringPool()->stringAt(type_spec->type_spec->id - 1);
+ ASSERT_TRUE(type_name16.has_value());
+ EXPECT_THAT(util::Utf16ToUtf8(*type_name16), StrEq("string"));
- ASSERT_THAT(LoadedPackage::GetEntry(type_spec->types[0], entry_index), NotNull());
+ ASSERT_TRUE(LoadedPackage::GetEntry(type_spec->types[0], entry_index).has_value());
}
// AAPT(2) generates resource tables with chunks in a certain order. The rule is that
@@ -205,7 +207,8 @@
ReadFileFromZipToString(GetTestDataPath() + "/out_of_order_types/out_of_order_types.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
ASSERT_THAT(loaded_arsc->GetPackages(), SizeIs(1u));
@@ -215,12 +218,10 @@
const TypeSpec* type_spec = package->GetTypeSpecByTypeIndex(0);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
type_spec = package->GetTypeSpecByTypeIndex(1);
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- ASSERT_THAT(type_spec->types[0], NotNull());
}
TEST(LoadedArscTest, LoadOverlayable) {
@@ -228,7 +229,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package = loaded_arsc->GetPackageById(
@@ -272,7 +274,8 @@
ASSERT_TRUE(
ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_NE(nullptr, loaded_arsc);
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
@@ -320,7 +323,8 @@
ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
"resources.arsc", &contents));
- std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+ std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(),
+ contents.length());
ASSERT_NE(nullptr, loaded_arsc);
const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
@@ -345,7 +349,7 @@
asset->getLength());
std::unique_ptr<const LoadedArsc> loaded_arsc =
- LoadedArsc::Load(data, nullptr, PROPERTY_LOADER);
+ LoadedArsc::Load(data.data(), data.length(), nullptr, PROPERTY_LOADER);
ASSERT_THAT(loaded_arsc, NotNull());
const LoadedPackage* package =
@@ -361,9 +365,8 @@
ASSERT_THAT(type_spec, NotNull());
ASSERT_THAT(type_spec->type_count, Ge(1u));
- const ResTable_type* type = type_spec->types[0];
- ASSERT_THAT(type, NotNull());
- ASSERT_THAT(LoadedPackage::GetEntry(type, entry_index), NotNull());
+ auto type = type_spec->types[0];
+ ASSERT_TRUE(LoadedPackage::GetEntry(type, entry_index).has_value());
}
// structs with size fields (like Res_value, ResTable_entry) should be
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 326474e..9aeb00c 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -442,22 +442,22 @@
ASSERT_LT(val.data, pool->size());
// Make sure a string with a truncated length is read to its correct length
- size_t str_len;
- const char* target_str8 = pool->string8At(val.data, &str_len);
- ASSERT_TRUE(target_str8 != NULL);
- ASSERT_EQ(size_t(40076), String8(target_str8, str_len).size());
- ASSERT_EQ(target_str8[40075], ']');
+ auto target_str8 = pool->string8At(val.data);
+ ASSERT_TRUE(target_str8.has_value());
+ ASSERT_EQ(size_t(40076), String8(target_str8->data(), target_str8->size()).size());
+ ASSERT_EQ(target_str8->data()[40075], ']');
- const char16_t* target_str16 = pool->stringAt(val.data, &str_len);
- ASSERT_TRUE(target_str16 != NULL);
- ASSERT_EQ(size_t(40076), String16(target_str16, str_len).size());
- ASSERT_EQ(target_str8[40075], (char16_t) ']');
+ auto target_str16 = pool->stringAt(val.data);
+ ASSERT_TRUE(target_str16.has_value());
+ ASSERT_EQ(size_t(40076), String16(target_str16->data(), target_str16->size()).size());
+ ASSERT_EQ(target_str8->data()[40075], (char16_t) ']');
// Load an edited apk with the null terminator removed from the end of the
// string
std::string invalid_contents;
- ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/length_decode/length_decode_invalid.apk",
- "resources.arsc", &invalid_contents));
+ ASSERT_TRUE(ReadFileFromZipToString(
+ GetTestDataPath() + "/length_decode/length_decode_invalid.apk", "resources.arsc",
+ &invalid_contents));
ResTable invalid_table;
ASSERT_EQ(NO_ERROR, invalid_table.add(invalid_contents.data(), invalid_contents.size()));
@@ -472,8 +472,8 @@
// Make sure a string with a truncated length that is not null terminated errors
// and does not return the string
- ASSERT_TRUE(invalid_pool->string8At(invalid_val.data, &str_len) == NULL);
- ASSERT_TRUE(invalid_pool->stringAt(invalid_val.data, &str_len) == NULL);
+ ASSERT_FALSE(invalid_pool->string8At(invalid_val.data).has_value());
+ ASSERT_FALSE(invalid_pool->stringAt(invalid_val.data).has_value());
}
} // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index a81bb6f..10c0a4f 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -73,11 +73,15 @@
return AssertionFailure() << "table has no string pool for block " << block;
}
- const String8 actual_str = pool->string8ObjectAt(val.data);
- if (String8(expected_str) != actual_str) {
- return AssertionFailure() << actual_str.string();
+ auto actual_str = pool->string8ObjectAt(val.data);
+ if (!actual_str.has_value()) {
+ return AssertionFailure() << "could not find string entry";
}
- return AssertionSuccess() << actual_str.string();
+
+ if (String8(expected_str) != *actual_str) {
+ return AssertionFailure() << actual_str->string();
+ }
+ return AssertionSuccess() << actual_str->string();
}
} // namespace android
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
index 594c39e..f3d60bb 100644
--- a/libs/androidfw/tests/Theme_bench.cpp
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -70,11 +70,8 @@
auto theme = assets.NewTheme();
theme->ApplyStyle(kStyleId, false /* force */);
- Res_value value;
- uint32_t flags;
-
while (state.KeepRunning()) {
- theme->GetAttribute(kAttrId, &value, &flags);
+ theme->GetAttribute(kAttrId);
}
}
BENCHMARK(BM_ThemeGetAttribute);
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 16b9c75..f658735 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -67,10 +67,7 @@
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
EXPECT_EQ(0u, theme->GetChangingConfigurations());
EXPECT_EQ(&assetmanager, theme->GetAssetManager());
-
- Res_value value;
- uint32_t flags;
- EXPECT_EQ(kInvalidCookie, theme->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ EXPECT_FALSE(theme->GetAttribute(app::R::attr::attr_one).has_value());
}
TEST_F(ThemeTest, SingleThemeNoParent) {
@@ -78,23 +75,19 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne));
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne).has_value());
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
-
- cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(2u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(2u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, SingleThemeWithParent) {
@@ -102,32 +95,28 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
-
- cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
- EXPECT_EQ(0, cookie);
+ value = theme->GetAttribute(app::R::attr::attr_two);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_STRING, value->type);
+ EXPECT_EQ(0, value->cookie);
EXPECT_EQ(std::string("string"),
- GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value.data));
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value->data));
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// This attribute should point to an attr_indirect, so the result should be 3.
- cookie = theme->GetAttribute(app::R::attr::attr_three, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(3u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_three);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(3u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, TryToUseBadResourceId) {
@@ -135,11 +124,8 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
-
- Res_value value;
- uint32_t flags;
- ASSERT_EQ(kInvalidCookie, theme->GetAttribute(0x7f000001, &value, &flags));
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_FALSE(theme->GetAttribute(0x7f000001));
}
TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
@@ -147,33 +133,29 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree).has_value());
// attr_one is still here from the base.
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_six
- cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the old attr_five (force=true was not used).
- cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
- EXPECT_EQ(app::R::string::string_one, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_five);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
+ EXPECT_EQ(app::R::string::string_one, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
@@ -181,33 +163,29 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo).has_value());
+ ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */).has_value());
// attr_one is still here from the base.
- cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_six
- cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// check for the new attr_five (force=true was used).
- cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(5u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme->GetAttribute(app::R::attr::attr_five);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(5u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, ResolveDynamicAttributesAndReferencesToSharedLibrary) {
@@ -216,28 +194,24 @@
{lib_two_assets_.get(), lib_one_assets_.get(), libclient_assets_.get()});
std::unique_ptr<Theme> theme = assetmanager.NewTheme();
- ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme->ApplyStyle(libclient::R::style::Theme, false /*force*/).has_value());
// The attribute should be resolved to the final value.
- cookie = theme->GetAttribute(libclient::R::attr::foo, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(700u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme->GetAttribute(libclient::R::attr::foo);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(700u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// The reference should be resolved to a TYPE_REFERENCE.
- cookie = theme->GetAttribute(libclient::R::attr::bar, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+ value = theme->GetAttribute(libclient::R::attr::bar);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_REFERENCE, value->type);
// lib_one is assigned package ID 0x03.
- EXPECT_EQ(3u, get_package_id(value.data));
- EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value.data));
- EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value.data));
+ EXPECT_EQ(3u, get_package_id(value->data));
+ EXPECT_EQ(get_type_id(lib_one::R::string::foo), get_type_id(value->data));
+ EXPECT_EQ(get_entry_id(lib_one::R::string::foo), get_entry_id(value->data));
}
TEST_F(ThemeTest, CopyThemeSameAssetManager) {
@@ -245,24 +219,20 @@
assetmanager.SetApkAssets({style_assets_.get()});
std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
- ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
-
- Res_value value;
- uint32_t flags;
- ApkAssetsCookie cookie;
+ ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne).has_value());
// attr_one is still here from the base.
- cookie = theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(1u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ auto value = theme_one->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(1u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
// attr_six is not here.
- EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags));
+ ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_six).has_value());
std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
- ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
+ ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree).has_value());
// Copy the theme to theme_one.
theme_one->SetTo(*theme_two);
@@ -271,14 +241,14 @@
theme_two->Clear();
// attr_one is now not here.
- EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ ASSERT_FALSE(theme_one->GetAttribute(app::R::attr::attr_one).has_value());
// attr_six is now here because it was copied.
- cookie = theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags);
- ASSERT_NE(kInvalidCookie, cookie);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
- EXPECT_EQ(6u, value.data);
- EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+ value = theme_one->GetAttribute(app::R::attr::attr_six);
+ ASSERT_TRUE(value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, value->type);
+ EXPECT_EQ(6u, value->data);
+ EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), value->flags);
}
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
@@ -291,39 +261,43 @@
style_assets_.get()});
auto theme_dst = assetmanager_dst.NewTheme();
- ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne));
+ ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne).has_value());
auto theme_src = assetmanager_src.NewTheme();
- ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One));
- ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One).has_value());
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo).has_value());
ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
- false /*force*/));
+ false /*force*/).has_value());
ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
- false /*force*/));
+ false /*force*/).has_value());
theme_dst->SetTo(*theme_src);
- Res_value value;
- uint32_t flags;
-
// System resources (present in destination asset manager).
- EXPECT_EQ(0, theme_dst->GetAttribute(R::attr::foreground, &value, &flags));
+ auto value = theme_dst->GetAttribute(R::attr::foreground);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
// The cookie of the style asset is 3 in the source and 2 in the destination.
// Check that the cookie has been rewritten to the destination values.
- EXPECT_EQ(2, theme_dst->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ value = theme_dst->GetAttribute(app::R::attr::attr_one);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(2, value->cookie);
// The cookie of the lib_one asset is 2 in the source and 1 in the destination.
// The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
// Check that the cookie and packages have been rewritten to the destination values.
- EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
- &flags));
- EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
- &flags));
+ value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
+
+ value = theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02));
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(1, value->cookie);
// attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
// correct after the value of attr2 had its package id rewritten to the destination package id.
- EXPECT_EQ(700, value.data);
+ EXPECT_EQ(700, value->data);
}
TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
@@ -335,28 +309,32 @@
auto theme_dst = assetmanager_dst.NewTheme();
auto theme_src = assetmanager_src.NewTheme();
- ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven));
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven).has_value());
theme_dst->SetTo(*theme_src);
- Res_value value;
- uint32_t flags;
-
// Allow inline resource values to be copied even if the source apk asset is not present in the
// destination.
- EXPECT_EQ(0, theme_dst->GetAttribute(0x0101021b /* android:versionCode */, &value, &flags));
+ auto value = theme_dst->GetAttribute(0x0101021b /* android:versionCode */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
// Do not copy strings since the data is an index into the values string pool of the source apk
// asset.
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010001 /* android:label */, &value, &flags));
+ EXPECT_FALSE(theme_dst->GetAttribute(0x01010001 /* android:label */).has_value());
// Do not copy values that reference another resource if the resource is not present in the
// destination.
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010002 /* android:icon */, &value, &flags));
- EXPECT_EQ(-1, theme_dst->GetAttribute(0x010100d1 /* android:tag */, &value, &flags));
+ EXPECT_FALSE(theme_dst->GetAttribute(0x01010002 /* android:icon */).has_value());
+ EXPECT_FALSE(theme_dst->GetAttribute(0x010100d1 /* android:tag */).has_value());
// Allow @empty to and @null to be copied.
- EXPECT_EQ(0, theme_dst->GetAttribute(0x010100d0 /* android:id */, &value, &flags));
- EXPECT_EQ(0, theme_dst->GetAttribute(0x01010000 /* android:theme */, &value, &flags));
+ value = theme_dst->GetAttribute(0x010100d0 /* android:id */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
+
+ value = theme_dst->GetAttribute(0x01010000 /* android:theme */);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(0, value->cookie);
}
} // namespace android
diff --git a/location/java/android/location/OWNERS b/location/java/android/location/OWNERS
index 383321b..6032144 100644
--- a/location/java/android/location/OWNERS
+++ b/location/java/android/location/OWNERS
@@ -1,6 +1,6 @@
# Bug component: 880425
-mstogaitis@google.com
+sooniln@google.com
wyattriley@google.com
-etn@google.com
+yuhany@google.com
weiwa@google.com
diff --git a/lowpan/java/android/net/lowpan/LowpanManager.java b/lowpan/java/android/net/lowpan/LowpanManager.java
index 76876ce..33b35e6 100644
--- a/lowpan/java/android/net/lowpan/LowpanManager.java
+++ b/lowpan/java/android/net/lowpan/LowpanManager.java
@@ -24,6 +24,10 @@
import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.BackgroundThread;
+
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
@@ -97,10 +101,14 @@
*
* @param context the application context
* @param service the Binder interface
- * @param looper the default Looper to run callbacks on
* @hide - hide this because it takes in a parameter of type ILowpanManager, which is a system
* private class.
*/
+ public LowpanManager(Context context, ILowpanManager service) {
+ this(context, service, BackgroundThread.get().getLooper());
+ }
+
+ @VisibleForTesting
public LowpanManager(Context context, ILowpanManager service, Looper looper) {
mContext = context;
mService = service;
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index c2168f1..e7e83eb 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -25,6 +25,7 @@
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
+import android.os.Process;
import android.os.SystemProperties;
import android.util.Log;
import android.util.Pair;
@@ -188,13 +189,14 @@
// COMMON CONSTANTS
private static final Range<Integer> POSITIVE_INTEGERS =
- Range.create(1, Integer.MAX_VALUE);
+ Range.create(1, Integer.MAX_VALUE);
private static final Range<Long> POSITIVE_LONGS =
- Range.create(1l, Long.MAX_VALUE);
+ Range.create(1L, Long.MAX_VALUE);
private static final Range<Rational> POSITIVE_RATIONALS =
- Range.create(new Rational(1, Integer.MAX_VALUE),
- new Rational(Integer.MAX_VALUE, 1));
- private static final Range<Integer> SIZE_RANGE = Range.create(1, 32768);
+ Range.create(new Rational(1, Integer.MAX_VALUE),
+ new Rational(Integer.MAX_VALUE, 1));
+ private static final Range<Integer> SIZE_RANGE =
+ Process.is64Bit() ? Range.create(1, 32768) : Range.create(1, 4096);
private static final Range<Integer> FRAME_RATE_RANGE = Range.create(0, 960);
private static final Range<Integer> BITRATE_RANGE = Range.create(0, 500000000);
private static final int DEFAULT_MAX_SUPPORTED_INSTANCES = 32;
@@ -1399,6 +1401,9 @@
/**
* Returns the range of supported video widths.
+ * <p class=note>
+ * 32-bit processes will not support resolutions larger than 4096x4096 due to
+ * the limited address space.
*/
public Range<Integer> getSupportedWidths() {
return mWidthRange;
@@ -1406,6 +1411,9 @@
/**
* Returns the range of supported video heights.
+ * <p class=note>
+ * 32-bit processes will not support resolutions larger than 4096x4096 due to
+ * the limited address space.
*/
public Range<Integer> getSupportedHeights() {
return mHeightRange;
@@ -1857,6 +1865,10 @@
&& aligned.mMaxMacroBlockRate >= otherAligned.mMaxMacroBlockRate);
}
+ /* package private */ boolean isEqualDimension(@NonNull PerformancePoint other) {
+ return mWidth == other.mWidth && mHeight == other.mHeight;
+ }
+
private @NonNull Size getCommonBlockSize(@NonNull PerformancePoint other) {
return new Size(
Math.max(mBlockSize.getWidth(), other.mBlockSize.getWidth()) * 16,
@@ -1997,6 +2009,9 @@
* Performance points assume a single active codec. For use cases where multiple
* codecs are active, should use that highest pixel count, and add the frame rates of
* each individual codec.
+ * <p class=note>
+ * Supported resolution could be further restricted for 32-bit processes due to
+ * the limited virtual memory space.
*/
@Nullable
public List<PerformancePoint> getSupportedPerformancePoints() {
@@ -2164,6 +2179,12 @@
if (size == null || size.getWidth() * size.getHeight() <= 0) {
continue;
}
+ if (size.getWidth() > SIZE_RANGE.getUpper()
+ || size.getHeight() > SIZE_RANGE.getUpper()) {
+ size = new Size(
+ Math.min(size.getWidth(), SIZE_RANGE.getUpper()),
+ Math.min(size.getHeight(), SIZE_RANGE.getUpper()));
+ }
Range<Long> range = Utils.parseLongRange(map.get(key), null);
if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
continue;
@@ -2193,6 +2214,29 @@
(a.getMaxMacroBlockRate() < b.getMaxMacroBlockRate() ? -1 : 1) :
(a.getMaxFrameRate() != b.getMaxFrameRate()) ?
(a.getMaxFrameRate() < b.getMaxFrameRate() ? -1 : 1) : 0));
+
+ // remove redundant points
+ for (int i = 1; i < ret.size(); ++i) {
+ PerformancePoint a = ret.get(i);
+ for (int j = 0; j < i; ++j) {
+ PerformancePoint b = ret.get(j);
+ if (b.isEqualDimension(a) && b.covers(a)) {
+ ret.set(i, null);
+ break;
+ }
+ }
+ }
+ int newSize = 0;
+ for (int i = 0; i < ret.size(); ++i) {
+ PerformancePoint a = ret.get(i);
+ if (a == null) {
+ continue;
+ }
+ ret.set(newSize, a);
+ ++newSize;
+ }
+ ret.setSize(newSize);
+
return Collections.unmodifiableList(ret);
}
diff --git a/packages/Connectivity/OWNERS b/packages/Connectivity/OWNERS
new file mode 100644
index 0000000..48e54da
--- /dev/null
+++ b/packages/Connectivity/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+include platform/frameworks/base:/services/core/java/com/android/server/net/OWNERS
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 51f69a9..2eba38e 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -180,7 +180,7 @@
<!-- Default state of tap to wake -->
<bool name="def_double_tap_to_wake">true</bool>
- <!-- Default for Settings.Secure.NFC_PAYMENT_COMPONENT -->
+ <!-- Default for Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT -->
<string name="def_nfc_payment_component"></string>
<!-- Default setting for ability to add users from the lock screen -->
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 757bbda..5d6c4c3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -154,6 +154,7 @@
<uses-permission android:name="android.permission.MANAGE_CONTENT_CAPTURE" />
<uses-permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS" />
<uses-permission android:name="android.permission.MANAGE_APP_PREDICTIONS" />
+ <uses-permission android:name="android.permission.MANAGE_SEARCH_UI" />
<uses-permission android:name="android.permission.NETWORK_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.SET_TIME" />
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 02815a57..63b9bb3 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -378,6 +378,9 @@
}
}
+ @Override
+ public void onEarlyReportFinished() {}
+
/**
* Reads bugreport id and links it to the bugreport info to track a bugreport that is in
* process. id is incremented in the dumpstate code.
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 0b8b352..aab0553 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1265,7 +1265,7 @@
@Override
public boolean bindBluetoothProfileService(int bluetoothProfile,
IBluetoothProfileServiceConnection proxy) {
- if (!mEnable) {
+ if (mState != BluetoothAdapter.STATE_ON) {
if (DBG) {
Slog.d(TAG, "Trying to bind to profile: " + bluetoothProfile
+ ", while Bluetooth was disabled");
@@ -1431,7 +1431,7 @@
mBluetoothLock.readLock().unlock();
}
- if (!mEnable || state != BluetoothAdapter.STATE_ON) {
+ if (state != BluetoothAdapter.STATE_ON) {
if (DBG) {
Slog.d(TAG, "Unable to bindService while Bluetooth is disabled");
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d867442..2c765bd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -113,7 +113,6 @@
import android.net.NetworkMonitorManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkProvider;
-import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
import android.net.NetworkSpecifier;
import android.net.NetworkStack;
@@ -129,6 +128,7 @@
import android.net.SocketKeepalive;
import android.net.TetheringManager;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.Uri;
import android.net.VpnManager;
import android.net.VpnService;
@@ -1780,14 +1780,6 @@
}
@Override
- @Deprecated
- public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
- Log.w(TAG, "Shame on UID " + Binder.getCallingUid()
- + " for calling the hidden API getNetworkQuotaInfo(). Shame!");
- return new NetworkQuotaInfo();
- }
-
- @Override
public boolean isActiveNetworkMetered() {
enforceAccessPermission();
@@ -2822,6 +2814,7 @@
break;
}
case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
+ // TODO: prevent loops, e.g., if a network declares itself as underlying.
if (!nai.supportsUnderlyingNetworks()) {
Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
break;
@@ -3421,6 +3414,7 @@
}
}
nai.clearLingerState();
+ propagateUnderlyingNetworkCapabilities(nai.network);
if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
mDefaultNetworkNai = null;
updateDataActivityTracking(null /* newNetwork */, nai);
@@ -3428,9 +3422,6 @@
ensureNetworkTransitionWakelock(nai.toShortString());
}
mLegacyTypeTracker.remove(nai, wasDefault);
- if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
- propagateUnderlyingNetworkCapabilities();
- }
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
if (nai.created) {
@@ -4819,17 +4810,35 @@
}
}
+ private Network[] underlyingNetworksOrDefault(Network[] underlyingNetworks) {
+ final Network defaultNetwork = getNetwork(getDefaultNetwork());
+ if (underlyingNetworks == null && defaultNetwork != null) {
+ // null underlying networks means to track the default.
+ underlyingNetworks = new Network[] { defaultNetwork };
+ }
+ return underlyingNetworks;
+ }
+
+ // Returns true iff |network| is an underlying network of |nai|.
+ private boolean hasUnderlyingNetwork(NetworkAgentInfo nai, Network network) {
+ // TODO: support more than one level of underlying networks, either via a fixed-depth search
+ // (e.g., 2 levels of underlying networks), or via loop detection, or....
+ if (!nai.supportsUnderlyingNetworks()) return false;
+ final Network[] underlying = underlyingNetworksOrDefault(nai.declaredUnderlyingNetworks);
+ return ArrayUtils.contains(underlying, network);
+ }
+
/**
- * Ask all networks with underlying networks to recompute and update their capabilities.
+ * Recompute the capabilities for any networks that had a specific network as underlying.
*
* When underlying networks change, such networks may have to update capabilities to reflect
* things like the metered bit, their transports, and so on. The capabilities are calculated
* immediately. This method runs on the ConnectivityService thread.
*/
- private void propagateUnderlyingNetworkCapabilities() {
+ private void propagateUnderlyingNetworkCapabilities(Network updatedNetwork) {
ensureRunningOnConnectivityServiceThread();
for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- if (nai.supportsUnderlyingNetworks()) {
+ if (updatedNetwork == null || hasUnderlyingNetwork(nai, updatedNetwork)) {
updateCapabilitiesForNetwork(nai);
}
}
@@ -5152,7 +5161,7 @@
loge("Starting user already has a VPN");
return;
}
- userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, userId, mKeyStore);
+ userVpn = new Vpn(mHandler.getLooper(), mContext, mNMS, mNetd, userId, mKeyStore);
mVpns.put(userId, userVpn);
if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
updateLockdownVpn();
@@ -6368,27 +6377,28 @@
* This method should never alter the agent's NetworkCapabilities, only store data in |nai|.
*/
private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
- nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
+ // Note: resetting the owner UID before storing the agent capabilities in NAI means that if
+ // the agent attempts to change the owner UID, then nai.declaredCapabilities will not
+ // actually be the same as the capabilities sent by the agent. Still, it is safer to reset
+ // the owner UID here and behave as if the agent had never tried to change it.
if (nai.networkCapabilities.getOwnerUid() != nc.getOwnerUid()) {
Log.e(TAG, nai.toShortString() + ": ignoring attempt to change owner from "
+ nai.networkCapabilities.getOwnerUid() + " to " + nc.getOwnerUid());
nc.setOwnerUid(nai.networkCapabilities.getOwnerUid());
}
+ nai.declaredCapabilities = new NetworkCapabilities(nc);
}
- /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+ /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */
@VisibleForTesting
void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
- @NonNull NetworkCapabilities caps, boolean declaredMetered) {
- final Network defaultNetwork = getNetwork(getDefaultNetwork());
- if (underlyingNetworks == null && defaultNetwork != null) {
- // null underlying networks means to track the default.
- underlyingNetworks = new Network[] { defaultNetwork };
- }
- int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ @NonNull NetworkCapabilities agentCaps, @NonNull NetworkCapabilities newNc) {
+ underlyingNetworks = underlyingNetworksOrDefault(underlyingNetworks);
+ int[] transportTypes = agentCaps.getTransportTypes();
int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
- boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+ // metered if any underlying is metered, or originally declared metered by the agent.
+ boolean metered = !agentCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
boolean roaming = false; // roaming if any underlying is roaming
boolean congested = false; // congested if any underlying is congested
boolean suspended = true; // suspended if all underlying are suspended
@@ -6434,13 +6444,13 @@
suspended = false;
}
- caps.setTransportTypes(transportTypes);
- caps.setLinkDownstreamBandwidthKbps(downKbps);
- caps.setLinkUpstreamBandwidthKbps(upKbps);
- caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
- caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
- caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
- caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
+ newNc.setTransportTypes(transportTypes);
+ newNc.setLinkDownstreamBandwidthKbps(downKbps);
+ newNc.setLinkUpstreamBandwidthKbps(upKbps);
+ newNc.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+ newNc.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+ newNc.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+ newNc.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
}
/**
@@ -6497,7 +6507,8 @@
}
if (nai.supportsUnderlyingNetworks()) {
- applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
+ applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, nai.declaredCapabilities,
+ newNc);
}
return newNc;
@@ -6576,11 +6587,8 @@
}
}
- if (!newNc.hasTransport(TRANSPORT_VPN)) {
- // Tell VPNs about updated capabilities, since they may need to
- // bubble those changes through.
- propagateUnderlyingNetworkCapabilities();
- }
+ // This network might have been underlying another network. Propagate its capabilities.
+ propagateUnderlyingNetworkCapabilities(nai.network);
if (!newNc.equalsTransportTypes(prevNc)) {
mDnsManager.updateTransportsForNetwork(
@@ -6622,6 +6630,16 @@
&& (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
}
+ private static UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
+ final UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.size()];
+ int index = 0;
+ for (UidRange range : ranges) {
+ stableRanges[index] = new UidRangeParcel(range.start, range.stop);
+ index++;
+ }
+ return stableRanges;
+ }
+
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) {
Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
@@ -6641,14 +6659,11 @@
// removing old range works because, unlike the filtering rules below, it's possible to
// add duplicate UID routing rules.
if (!newRanges.isEmpty()) {
- final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
- newRanges.toArray(addedRangesArray);
- mNMS.addVpnUidRanges(nai.network.getNetId(), addedRangesArray);
+ mNetd.networkAddUidRanges(nai.network.netId, toUidRangeStableParcels(newRanges));
}
if (!prevRanges.isEmpty()) {
- final UidRange[] removedRangesArray = new UidRange[prevRanges.size()];
- prevRanges.toArray(removedRangesArray);
- mNMS.removeVpnUidRanges(nai.network.getNetId(), removedRangesArray);
+ mNetd.networkRemoveUidRanges(
+ nai.network.netId, toUidRangeStableParcels(prevRanges));
}
final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
@@ -6903,8 +6918,10 @@
updateTcpBufferSizes(null != newNetwork
? newNetwork.linkProperties.getTcpBufferSizes() : null);
notifyIfacesChangedForNetworkStats();
- // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
- propagateUnderlyingNetworkCapabilities();
+ // Fix up the NetworkCapabilities of any networks that have this network as underlying.
+ if (newNetwork != null) {
+ propagateUnderlyingNetworkCapabilities(newNetwork.network);
+ }
}
private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -7360,13 +7377,11 @@
networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_FOREGROUND);
if (!createNativeNetwork(networkAgent)) return;
- if (networkAgent.isVPN()) {
- // Initialize the VPN capabilities to their starting values according to the
- // underlying networks. This will avoid a spurious callback to
- // onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
- // the VPN would switch from its default, blank capabilities to those
- // that reflect the capabilities of its underlying networks.
- propagateUnderlyingNetworkCapabilities();
+ if (networkAgent.supportsUnderlyingNetworks()) {
+ // Initialize the network's capabilities to their starting values according to the
+ // underlying networks. This ensures that the capabilities are correct before
+ // anything happens to the network.
+ updateCapabilitiesForNetwork(networkAgent);
}
networkAgent.created = true;
}
@@ -7408,10 +7423,6 @@
// doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
- if (networkAgent.supportsUnderlyingNetworks()) {
- propagateUnderlyingNetworkCapabilities();
- }
-
// Consider network even though it is not yet validated.
rematchAllNetworksAndRequests();
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 5e86f85..636da6f 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -60,7 +60,6 @@
import android.net.NetworkStats;
import android.net.RouteInfo;
import android.net.TetherStatsParcel;
-import android.net.UidRange;
import android.net.UidRangeParcel;
import android.net.shared.NetdUtils;
import android.net.shared.RouteUtils;
@@ -91,7 +90,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
-import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
@@ -420,8 +418,6 @@
getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
- FrameworkStatsLog.write_non_chained(
- FrameworkStatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
}
@@ -432,8 +428,6 @@
getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
- FrameworkStatsLog.write_non_chained(
- FrameworkStatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
}
@@ -1393,38 +1387,6 @@
}
}
- private static UidRangeParcel makeUidRangeParcel(int start, int stop) {
- UidRangeParcel range = new UidRangeParcel();
- range.start = start;
- range.stop = stop;
- return range;
- }
-
- private static UidRangeParcel[] toStableParcels(UidRange[] ranges) {
- UidRangeParcel[] stableRanges = new UidRangeParcel[ranges.length];
- for (int i = 0; i < ranges.length; i++) {
- stableRanges[i] = makeUidRangeParcel(ranges[i].start, ranges[i].stop);
- }
- return stableRanges;
- }
-
- @Override
- public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges)
- throws ServiceSpecificException {
- NetworkStack.checkNetworkStackPermission(mContext);
- try {
- mNetdService.networkRejectNonSecureVpn(add, toStableParcels(uidRanges));
- } catch (ServiceSpecificException e) {
- Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
- + ": netd command failed", e);
- throw e;
- } catch (RemoteException e) {
- Log.w(TAG, "setAllowOnlyVpnForUids(" + add + ", " + Arrays.toString(uidRanges) + ")"
- + ": netd command failed", e);
- throw e.rethrowAsRuntimeException();
- }
- }
-
private void applyUidCleartextNetworkPolicy(int uid, int policy) {
final int policyValue;
switch (policy) {
@@ -1553,27 +1515,6 @@
}
@Override
- public void addVpnUidRanges(int netId, UidRange[] ranges) {
- NetworkStack.checkNetworkStackPermission(mContext);
-
- try {
- mNetdService.networkAddUidRanges(netId, toStableParcels(ranges));
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
- public void removeVpnUidRanges(int netId, UidRange[] ranges) {
- NetworkStack.checkNetworkStackPermission(mContext);
- try {
- mNetdService.networkRemoveUidRanges(netId, toStableParcels(ranges));
- } catch (RemoteException | ServiceSpecificException e) {
- throw new IllegalStateException(e);
- }
- }
-
- @Override
public void setFirewallEnabled(boolean enabled) {
enforceSystemUid();
try {
@@ -1616,7 +1557,7 @@
ranges = new UidRangeParcel[] {
// TODO: is there a better way of finding all existing users? If so, we could
// specify their ranges here.
- makeUidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
+ new UidRangeParcel(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
};
// ... except for the UIDs that have allow rules.
synchronized (mRulesLock) {
@@ -1647,7 +1588,7 @@
for (int i = 0; i < ranges.length; i++) {
if (rules.valueAt(i) == FIREWALL_RULE_DENY) {
int uid = rules.keyAt(i);
- ranges[numUids] = makeUidRangeParcel(uid, uid);
+ ranges[numUids] = new UidRangeParcel(uid, uid);
numUids++;
}
}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index ff0596c..dd497a6 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4612,14 +4612,7 @@
// Create package obb and data dir if it doesn't exist.
int appUid = UserHandle.getUid(userId, mPmInternal.getPackage(pkg).getUid());
- File file = new File(packageObbDir);
- if (!file.exists()) {
- vold.setupAppDir(packageObbDir, appUid);
- }
- file = new File(packageDataDir);
- if (!file.exists()) {
- vold.setupAppDir(packageDataDir, appUid);
- }
+ vold.ensureAppDirsCreated(new String[] {packageObbDir, packageDataDir}, appUid);
}
} catch (ServiceManager.ServiceNotFoundException | RemoteException e) {
Slog.e(TAG, "Unable to create obb and data directories for " + processName,e);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 090ac54..1ade8e7 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -688,6 +688,8 @@
if (update) {
mWorker.scheduleSync("modem-data", BatteryExternalStatsWorker.UPDATE_RADIO);
}
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
public void notePhoneOn() {
@@ -869,6 +871,8 @@
}
mStats.noteWifiRadioPowerState(powerState, tsNanos, uid);
}
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
public void noteWifiRunning(WorkSource ws) {
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index ccd1f3b..52b9f5c 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -138,9 +138,10 @@
// not guaranteed to be current or correct, or even to exist.
public @Nullable Network[] declaredUnderlyingNetworks;
- // Whether this network is always metered even if its underlying networks are unmetered.
- // Only relevant if #supportsUnderlyingNetworks is true.
- public boolean declaredMetered;
+ // The capabilities originally announced by the NetworkAgent, regardless of any capabilities
+ // that were added or removed due to this network's underlying networks.
+ // Only set if #supportsUnderlyingNetworks is true.
+ public @Nullable NetworkCapabilities declaredCapabilities;
// Indicates if netd has been told to create this Network. From this point on the appropriate
// routing rules are setup and routes are added so packets can begin flowing over the Network.
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 1129899..b5f20d7 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -36,6 +36,7 @@
import android.net.TcpKeepalivePacketData;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.TcpRepairWindow;
+import android.net.util.KeepalivePacketDataUtil;
import android.os.Handler;
import android.os.MessageQueue;
import android.os.Messenger;
@@ -112,7 +113,7 @@
throws InvalidPacketException, InvalidSocketException {
try {
final TcpKeepalivePacketDataParcelable tcpDetails = switchToRepairMode(fd);
- return TcpKeepalivePacketData.tcpKeepalivePacket(tcpDetails);
+ return KeepalivePacketDataUtil.fromStableParcelable(tcpDetails);
} catch (InvalidPacketException | InvalidSocketException e) {
switchOutOfRepairMode(fd);
throw e;
@@ -122,7 +123,7 @@
* Switch the tcp socket to repair mode and query detail tcp information.
*
* @param fd the fd of socket on which to use keepalive offload.
- * @return a {@link TcpKeepalivePacketData#TcpKeepalivePacketDataParcelable} object for current
+ * @return a {@link TcpKeepalivePacketDataParcelable} object for current
* tcp/ip information.
*/
private static TcpKeepalivePacketDataParcelable switchToRepairMode(FileDescriptor fd)
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 66bb4d7..cabfbc0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -48,6 +48,7 @@
import android.content.pm.UserInfo;
import android.net.ConnectivityManager;
import android.net.DnsResolver;
+import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.Ikev2VpnProfile;
import android.net.IpPrefix;
@@ -68,6 +69,7 @@
import android.net.NetworkRequest;
import android.net.RouteInfo;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.ipsec.ike.ChildSessionCallback;
@@ -188,7 +190,8 @@
private PendingIntent mStatusIntent;
private volatile boolean mEnableTeardown = true;
- private final INetworkManagementService mNetd;
+ private final INetworkManagementService mNms;
+ private final INetd mNetd;
@VisibleForTesting
protected VpnConfig mConfig;
private final NetworkProvider mNetworkProvider;
@@ -234,7 +237,7 @@
* @see mLockdown
*/
@GuardedBy("this")
- private final Set<UidRange> mBlockedUidsAsToldToNetd = new ArraySet<>();
+ private final Set<UidRangeParcel> mBlockedUidsAsToldToNetd = new ArraySet<>();
// The user id of initiating VPN.
private final int mUserId;
@@ -363,22 +366,23 @@
}
}
- public Vpn(Looper looper, Context context, INetworkManagementService netService,
+ public Vpn(Looper looper, Context context, INetworkManagementService netService, INetd netd,
@UserIdInt int userId, @NonNull KeyStore keyStore) {
- this(looper, context, new Dependencies(), netService, userId, keyStore,
+ this(looper, context, new Dependencies(), netService, netd, userId, keyStore,
new SystemServices(context), new Ikev2SessionCreator());
}
@VisibleForTesting
protected Vpn(Looper looper, Context context, Dependencies deps,
- INetworkManagementService netService,
+ INetworkManagementService netService, INetd netd,
int userId, @NonNull KeyStore keyStore, SystemServices systemServices,
Ikev2SessionCreator ikev2SessionCreator) {
mContext = context;
mConnectivityManager = mContext.getSystemService(ConnectivityManager.class);
mUserIdContext = context.createContextAsUser(UserHandle.of(userId), 0 /* flags */);
mDeps = deps;
- mNetd = netService;
+ mNms = netService;
+ mNetd = netd;
mUserId = userId;
mLooper = looper;
mSystemServices = systemServices;
@@ -912,7 +916,7 @@
}
try {
- mNetd.denyProtect(mOwnerUID);
+ mNms.denyProtect(mOwnerUID);
} catch (Exception e) {
Log.wtf(TAG, "Failed to disallow UID " + mOwnerUID + " to call protect() " + e);
}
@@ -922,7 +926,7 @@
mOwnerUID = getAppUid(newPackage, mUserId);
mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
try {
- mNetd.allowProtect(mOwnerUID);
+ mNms.allowProtect(mOwnerUID);
} catch (Exception e) {
Log.wtf(TAG, "Failed to allow UID " + mOwnerUID + " to call protect() " + e);
}
@@ -1579,24 +1583,25 @@
exemptedPackages = new ArrayList<>(mLockdownAllowlist);
exemptedPackages.add(mPackage);
}
- final Set<UidRange> rangesToTellNetdToRemove = new ArraySet<>(mBlockedUidsAsToldToNetd);
+ final Set<UidRangeParcel> rangesToTellNetdToRemove =
+ new ArraySet<>(mBlockedUidsAsToldToNetd);
- final Set<UidRange> rangesToTellNetdToAdd;
+ final Set<UidRangeParcel> rangesToTellNetdToAdd;
if (enforce) {
- final Set<UidRange> rangesThatShouldBeBlocked =
+ final Set<UidRange> restrictedProfilesRanges =
createUserAndRestrictedProfilesRanges(mUserId,
- /* allowedApplications */ null,
- /* disallowedApplications */ exemptedPackages);
+ /* allowedApplications */ null,
+ /* disallowedApplications */ exemptedPackages);
+ final Set<UidRangeParcel> rangesThatShouldBeBlocked = new ArraySet<>();
// The UID range of the first user (0-99999) would block the IPSec traffic, which comes
// directly from the kernel and is marked as uid=0. So we adjust the range to allow
// it through (b/69873852).
- for (UidRange range : rangesThatShouldBeBlocked) {
- if (range.start == 0) {
- rangesThatShouldBeBlocked.remove(range);
- if (range.stop != 0) {
- rangesThatShouldBeBlocked.add(new UidRange(1, range.stop));
- }
+ for (UidRange range : restrictedProfilesRanges) {
+ if (range.start == 0 && range.stop != 0) {
+ rangesThatShouldBeBlocked.add(new UidRangeParcel(1, range.stop));
+ } else if (range.start != 0) {
+ rangesThatShouldBeBlocked.add(new UidRangeParcel(range.start, range.stop));
}
}
@@ -1628,13 +1633,13 @@
* including added ranges that already existed or removed ones that didn't.
*/
@GuardedBy("this")
- private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRange> ranges) {
+ private boolean setAllowOnlyVpnForUids(boolean enforce, Collection<UidRangeParcel> ranges) {
if (ranges.size() == 0) {
return true;
}
- final UidRange[] rangesArray = ranges.toArray(new UidRange[ranges.size()]);
+ final UidRangeParcel[] stableRanges = ranges.toArray(new UidRangeParcel[ranges.size()]);
try {
- mNetd.setAllowOnlyVpnForUids(enforce, rangesArray);
+ mNetd.networkRejectNonSecureVpn(enforce, stableRanges);
} catch (RemoteException | RuntimeException e) {
Log.e(TAG, "Updating blocked=" + enforce
+ " for UIDs " + Arrays.toString(ranges.toArray()) + " failed", e);
@@ -1849,10 +1854,20 @@
if (mNetworkInfo.isConnected()) {
return !appliesToUid(uid);
} else {
- return UidRange.containsUid(mBlockedUidsAsToldToNetd, uid);
+ return containsUid(mBlockedUidsAsToldToNetd, uid);
}
}
+ private boolean containsUid(Collection<UidRangeParcel> ranges, int uid) {
+ if (ranges == null) return false;
+ for (UidRangeParcel range : ranges) {
+ if (range.start <= uid && uid <= range.stop) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void updateAlwaysOnNotification(DetailedState networkState) {
final boolean visible = (mAlwaysOn && networkState != DetailedState.CONNECTED);
@@ -2495,7 +2510,7 @@
address /* unused */,
address /* unused */,
network);
- mNetd.setInterfaceUp(mTunnelIface.getInterfaceName());
+ mNms.setInterfaceUp(mTunnelIface.getInterfaceName());
mSession = mIkev2SessionCreator.createIkeSession(
mContext,
diff --git a/services/core/java/com/android/server/location/OWNERS b/services/core/java/com/android/server/location/OWNERS
index c2c95e6..696a0c2 100644
--- a/services/core/java/com/android/server/location/OWNERS
+++ b/services/core/java/com/android/server/location/OWNERS
@@ -1,8 +1 @@
-aadmal@google.com
-arthuri@google.com
-bduddie@google.com
-gomo@google.com
-sooniln@google.com
-weiwa@google.com
-wyattriley@google.com
-yuhany@google.com
+file:/location/java/android/location/OWNERS
diff --git a/services/core/java/com/android/server/location/contexthub/OWNERS b/services/core/java/com/android/server/location/contexthub/OWNERS
new file mode 100644
index 0000000..d4393d6
--- /dev/null
+++ b/services/core/java/com/android/server/location/contexthub/OWNERS
@@ -0,0 +1,2 @@
+arthuri@google.com
+bduddie@google.com
diff --git a/services/core/java/com/android/server/locksettings/OWNERS b/services/core/java/com/android/server/locksettings/OWNERS
index dad6e39..08b8a8c 100644
--- a/services/core/java/com/android/server/locksettings/OWNERS
+++ b/services/core/java/com/android/server/locksettings/OWNERS
@@ -1,2 +1,3 @@
jaggies@google.com
kchyn@google.com
+rubinxu@google.com
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
index 5787f7c4..8d5f553 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowManager.java
@@ -15,20 +15,15 @@
*/
package com.android.server.locksettings;
-
import static android.os.UserHandle.USER_SYSTEM;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.UserInfo;
-import android.hardware.rebootescrow.IRebootEscrow;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.ServiceSpecificException;
import android.os.SystemClock;
import android.os.UserManager;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.util.Slog;
@@ -44,7 +39,6 @@
import java.util.Date;
import java.util.List;
import java.util.Locale;
-import java.util.NoSuchElementException;
class RebootEscrowManager {
private static final String TAG = "RebootEscrowManager";
@@ -116,8 +110,24 @@
static class Injector {
protected Context mContext;
+ private final RebootEscrowProviderInterface mRebootEscrowProvider;
+
Injector(Context context) {
mContext = context;
+ RebootEscrowProviderInterface rebootEscrowProvider = null;
+ // TODO(xunchang) add implementation for server based ror.
+ if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_OTA,
+ "server_based_ror_enabled", false)) {
+ Slog.e(TAG, "Server based ror isn't implemented yet.");
+ } else {
+ rebootEscrowProvider = new RebootEscrowProviderHalImpl();
+ }
+
+ if (rebootEscrowProvider != null && rebootEscrowProvider.hasRebootEscrowSupport()) {
+ mRebootEscrowProvider = rebootEscrowProvider;
+ } else {
+ mRebootEscrowProvider = null;
+ }
}
public Context getContext() {
@@ -128,15 +138,8 @@
return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
}
- @Nullable
- public IRebootEscrow getRebootEscrow() {
- try {
- return IRebootEscrow.Stub.asInterface(ServiceManager.getService(
- "android.hardware.rebootescrow.IRebootEscrow/default"));
- } catch (NoSuchElementException e) {
- Slog.i(TAG, "Device doesn't implement RebootEscrow HAL");
- }
- return null;
+ public RebootEscrowProviderInterface getRebootEscrowProvider() {
+ return mRebootEscrowProvider;
}
public int getBootCount() {
@@ -210,45 +213,18 @@
}
private RebootEscrowKey getAndClearRebootEscrowKey() {
- IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
- if (rebootEscrow == null) {
- Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable");
+ RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+ if (rebootEscrowProvider == null) {
+ Slog.w(TAG,
+ "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
return null;
}
- try {
- byte[] escrowKeyBytes = rebootEscrow.retrieveKey();
- if (escrowKeyBytes == null) {
- Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key");
- return null;
- } else if (escrowKeyBytes.length != 32) {
- Slog.e(TAG, "IRebootEscrow returned key of incorrect size "
- + escrowKeyBytes.length);
- return null;
- }
-
- // Make sure we didn't get the null key.
- int zero = 0;
- for (int i = 0; i < escrowKeyBytes.length; i++) {
- zero |= escrowKeyBytes[i];
- }
- if (zero == 0) {
- Slog.w(TAG, "IRebootEscrow returned an all-zeroes key");
- return null;
- }
-
- // Overwrite the existing key with the null key
- rebootEscrow.storeKey(new byte[32]);
-
+ RebootEscrowKey key = rebootEscrowProvider.getAndClearRebootEscrowKey(null);
+ if (key != null) {
mEventLog.addEntry(RebootEscrowEvent.RETRIEVED_STORED_KEK);
- return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
- } catch (RemoteException e) {
- Slog.w(TAG, "Could not retrieve escrow data");
- return null;
- } catch (ServiceSpecificException e) {
- Slog.w(TAG, "Got service-specific exception: " + e.errorCode);
- return null;
}
+ return key;
}
private boolean restoreRebootEscrowForUser(@UserIdInt int userId, RebootEscrowKey key) {
@@ -279,9 +255,9 @@
return;
}
- IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
- if (rebootEscrow == null) {
- Slog.w(TAG, "Reboot escrow requested, but RebootEscrow HAL is unavailable");
+ if (mInjector.getRebootEscrowProvider() == null) {
+ Slog.w(TAG,
+ "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
return;
}
@@ -293,6 +269,7 @@
final RebootEscrowData escrowData;
try {
+ // TODO(xunchang) further wrap the escrowData with a key from keystore.
escrowData = RebootEscrowData.fromSyntheticPassword(escrowKey, spVersion,
syntheticPassword);
} catch (IOException e) {
@@ -330,18 +307,16 @@
mRebootEscrowWanted = false;
setRebootEscrowReady(false);
- IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
- if (rebootEscrow == null) {
+
+ RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+ if (rebootEscrowProvider == null) {
+ Slog.w(TAG,
+ "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
return;
}
mStorage.removeKey(REBOOT_ESCROW_ARMED_KEY, USER_SYSTEM);
-
- try {
- rebootEscrow.storeKey(new byte[32]);
- } catch (RemoteException | ServiceSpecificException e) {
- Slog.w(TAG, "Could not call RebootEscrow HAL to shred key");
- }
+ rebootEscrowProvider.clearRebootEscrowKey();
List<UserInfo> users = mUserManager.getUsers();
for (UserInfo user : users) {
@@ -356,9 +331,10 @@
return false;
}
- IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
- if (rebootEscrow == null) {
- Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable");
+ RebootEscrowProviderInterface rebootEscrowProvider = mInjector.getRebootEscrowProvider();
+ if (rebootEscrowProvider == null) {
+ Slog.w(TAG,
+ "Had reboot escrow data for users, but RebootEscrowProvider is unavailable");
return false;
}
@@ -372,15 +348,7 @@
return false;
}
- boolean armedRebootEscrow = false;
- try {
- rebootEscrow.storeKey(escrowKey.getKeyBytes());
- armedRebootEscrow = true;
- Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL");
- } catch (RemoteException | ServiceSpecificException e) {
- Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
- }
-
+ boolean armedRebootEscrow = rebootEscrowProvider.storeRebootEscrowKey(escrowKey, null);
if (armedRebootEscrow) {
mStorage.setInt(REBOOT_ESCROW_ARMED_KEY, mInjector.getBootCount(), USER_SYSTEM);
mEventLog.addEntry(RebootEscrowEvent.SET_ARMED_STATUS);
@@ -397,7 +365,7 @@
}
boolean prepareRebootEscrow() {
- if (mInjector.getRebootEscrow() == null) {
+ if (mInjector.getRebootEscrowProvider() == null) {
return false;
}
@@ -408,7 +376,7 @@
}
boolean clearRebootEscrow() {
- if (mInjector.getRebootEscrow() == null) {
+ if (mInjector.getRebootEscrowProvider() == null) {
return false;
}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
new file mode 100644
index 0000000..6c1040b
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderHalImpl.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.server.locksettings;
+
+import android.annotation.Nullable;
+import android.hardware.rebootescrow.IRebootEscrow;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.NoSuchElementException;
+
+import javax.crypto.SecretKey;
+
+/**
+ * An implementation of the {@link RebootEscrowProviderInterface} by calling the RebootEscrow HAL.
+ */
+class RebootEscrowProviderHalImpl implements RebootEscrowProviderInterface {
+ private static final String TAG = "RebootEscrowProvider";
+
+ private final Injector mInjector;
+
+ static class Injector {
+ @Nullable
+ public IRebootEscrow getRebootEscrow() {
+ try {
+ return IRebootEscrow.Stub.asInterface(ServiceManager.getService(
+ "android.hardware.rebootescrow.IRebootEscrow/default"));
+ } catch (NoSuchElementException e) {
+ Slog.i(TAG, "Device doesn't implement RebootEscrow HAL");
+ }
+ return null;
+ }
+ }
+
+ RebootEscrowProviderHalImpl() {
+ mInjector = new Injector();
+ }
+
+ @VisibleForTesting
+ RebootEscrowProviderHalImpl(Injector injector) {
+ mInjector = injector;
+ }
+
+ @Override
+ public boolean hasRebootEscrowSupport() {
+ return mInjector.getRebootEscrow() != null;
+ }
+
+ @Override
+ public RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey) {
+ IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+ if (rebootEscrow == null) {
+ Slog.w(TAG, "Had reboot escrow data for users, but RebootEscrow HAL is unavailable");
+ return null;
+ }
+
+ try {
+ byte[] escrowKeyBytes = rebootEscrow.retrieveKey();
+ if (escrowKeyBytes == null) {
+ Slog.w(TAG, "Had reboot escrow data for users, but could not retrieve key");
+ return null;
+ } else if (escrowKeyBytes.length != 32) {
+ Slog.e(TAG, "IRebootEscrow returned key of incorrect size "
+ + escrowKeyBytes.length);
+ return null;
+ }
+
+ // Make sure we didn't get the null key.
+ int zero = 0;
+ for (int i = 0; i < escrowKeyBytes.length; i++) {
+ zero |= escrowKeyBytes[i];
+ }
+ if (zero == 0) {
+ Slog.w(TAG, "IRebootEscrow returned an all-zeroes key");
+ return null;
+ }
+
+ // Overwrite the existing key with the null key
+ rebootEscrow.storeKey(new byte[32]);
+
+ return RebootEscrowKey.fromKeyBytes(escrowKeyBytes);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Could not retrieve escrow data");
+ return null;
+ } catch (ServiceSpecificException e) {
+ Slog.w(TAG, "Got service-specific exception: " + e.errorCode);
+ return null;
+ }
+ }
+
+ @Override
+ public void clearRebootEscrowKey() {
+ IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+ if (rebootEscrow == null) {
+ return;
+ }
+
+ try {
+ rebootEscrow.storeKey(new byte[32]);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Slog.w(TAG, "Could not call RebootEscrow HAL to shred key");
+ }
+
+ }
+
+ @Override
+ public boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey) {
+ IRebootEscrow rebootEscrow = mInjector.getRebootEscrow();
+ if (rebootEscrow == null) {
+ Slog.w(TAG, "Escrow marked as ready, but RebootEscrow HAL is unavailable");
+ return false;
+ }
+
+ try {
+ // The HAL interface only accept 32 bytes data. And the encrypted bytes for the escrow
+ // key may exceed that limit. So we just store the raw key bytes here.
+ rebootEscrow.storeKey(escrowKey.getKeyBytes());
+ Slog.i(TAG, "Reboot escrow key stored with RebootEscrow HAL");
+ return true;
+ } catch (RemoteException | ServiceSpecificException e) {
+ Slog.e(TAG, "Failed escrow secret to RebootEscrow HAL", e);
+ }
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
new file mode 100644
index 0000000..857ad5f
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowProviderInterface.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package com.android.server.locksettings;
+
+import javax.crypto.SecretKey;
+
+/**
+ * Provides APIs for {@link RebootEscrowManager} to access and manage the reboot escrow key.
+ * Implementations need to find a way to persist the key across a reboot, and securely discards the
+ * persisted copy.
+ *
+ * @hide
+ */
+public interface RebootEscrowProviderInterface {
+ /**
+ * Returns true if the secure store/discard of reboot escrow key is supported.
+ */
+ boolean hasRebootEscrowSupport();
+
+ /**
+ * Returns the stored RebootEscrowKey, and clears the storage. If the stored key is encrypted,
+ * use the input key to decrypt the RebootEscrowKey. Returns null on failure.
+ */
+ RebootEscrowKey getAndClearRebootEscrowKey(SecretKey decryptionKey);
+
+ /**
+ * Clears the stored RebootEscrowKey.
+ */
+ void clearRebootEscrowKey();
+
+ /**
+ * Saves the given RebootEscrowKey, optionally encrypt the storage with the encryptionKey.
+ */
+ boolean storeRebootEscrowKey(RebootEscrowKey escrowKey, SecretKey encryptionKey);
+}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 0b3cdae..7afa81a 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -165,11 +165,13 @@
private void buildBluetoothRoutes() {
mBluetoothRoutes.clear();
- for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
- if (device.isConnected()) {
- BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
- if (newBtRoute.connectedProfiles.size() > 0) {
- mBluetoothRoutes.put(device.getAddress(), newBtRoute);
+ if (mBluetoothAdapter.getBondedDevices() != null) {
+ for (BluetoothDevice device : mBluetoothAdapter.getBondedDevices()) {
+ if (device.isConnected()) {
+ BluetoothRouteInfo newBtRoute = createBluetoothRoute(device);
+ if (newBtRoute.connectedProfiles.size() > 0) {
+ mBluetoothRoutes.put(device.getAddress(), newBtRoute);
+ }
}
}
}
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index 47fcc08..dd507a3 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -297,9 +297,8 @@
}
@Override
- public void onUiIntensiveBugreportDumpsFinished(String callingPackage)
- throws RemoteException {
- mListener.onUiIntensiveBugreportDumpsFinished(callingPackage);
+ public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
+ mListener.onUiIntensiveBugreportDumpsFinished();
}
@Override
diff --git a/services/core/java/com/android/server/policy/OWNERS b/services/core/java/com/android/server/policy/OWNERS
index 0862c05..d25ec4a 100644
--- a/services/core/java/com/android/server/policy/OWNERS
+++ b/services/core/java/com/android/server/policy/OWNERS
@@ -1 +1,2 @@
include /services/core/java/com/android/server/wm/OWNERS
+include /services/core/java/com/android/server/input/OWNERS
diff --git a/services/core/java/com/android/server/recoverysystem/OWNERS b/services/core/java/com/android/server/recoverysystem/OWNERS
new file mode 100644
index 0000000..79ded0d
--- /dev/null
+++ b/services/core/java/com/android/server/recoverysystem/OWNERS
@@ -0,0 +1,2 @@
+rvrolyk@google.com
+zhaojiac@google.com
diff --git a/services/core/java/com/android/server/timedetector/OWNERS b/services/core/java/com/android/server/timedetector/OWNERS
index 09447a9..8f80897 100644
--- a/services/core/java/com/android/server/timedetector/OWNERS
+++ b/services/core/java/com/android/server/timedetector/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorService.java b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
index 6dac6b1..84776ea 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorService.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorService.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ITimeDetectorService;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
@@ -122,6 +123,14 @@
mHandler.post(() -> mTimeDetectorStrategy.suggestNetworkTime(timeSignal));
}
+ @Override
+ public void suggestGnssTime(@NonNull GnssTimeSuggestion timeSignal) {
+ enforceSuggestGnssTimePermission();
+ Objects.requireNonNull(timeSignal);
+
+ mHandler.post(() -> mTimeDetectorStrategy.suggestGnssTime(timeSignal));
+ }
+
/** Internal method for handling the auto time setting being changed. */
@VisibleForTesting
public void handleAutoTimeDetectionChanged() {
@@ -153,4 +162,10 @@
android.Manifest.permission.SET_TIME,
"set time");
}
+
+ private void enforceSuggestGnssTimePermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.SET_TIME,
+ "suggest gnss time");
+ }
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
index abd4c8c..de6412c 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategy.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -40,7 +41,7 @@
*/
public interface TimeDetectorStrategy {
- @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK })
+ @IntDef({ ORIGIN_TELEPHONY, ORIGIN_MANUAL, ORIGIN_NETWORK, ORIGIN_GNSS })
@Retention(RetentionPolicy.SOURCE)
@interface Origin {}
@@ -56,6 +57,10 @@
@Origin
int ORIGIN_NETWORK = 3;
+ /** Used when a time value originated from a gnss signal. */
+ @Origin
+ int ORIGIN_GNSS = 4;
+
/** Processes the suggested time from telephony sources. */
void suggestTelephonyTime(@NonNull TelephonyTimeSuggestion timeSuggestion);
@@ -70,6 +75,9 @@
/** Processes the suggested time from network sources. */
void suggestNetworkTime(@NonNull NetworkTimeSuggestion timeSuggestion);
+ /** Processes the suggested time from gnss sources. */
+ void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion);
+
/**
* Handles the auto-time configuration changing For example, when the auto-time setting is
* toggled on or off.
@@ -102,6 +110,8 @@
return "network";
case ORIGIN_TELEPHONY:
return "telephony";
+ case ORIGIN_GNSS:
+ return "gnss";
default:
throw new IllegalArgumentException("origin=" + origin);
}
@@ -119,6 +129,8 @@
return ORIGIN_NETWORK;
case "telephony":
return ORIGIN_TELEPHONY;
+ case "gnss":
+ return ORIGIN_GNSS;
default:
throw new IllegalArgumentException("originString=" + originString);
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index b3c8c90..6fe3782 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -23,6 +23,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AlarmManager;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -109,6 +110,10 @@
private final ReferenceWithHistory<NetworkTimeSuggestion> mLastNetworkSuggestion =
new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+ @GuardedBy("this")
+ private final ReferenceWithHistory<GnssTimeSuggestion> mLastGnssSuggestion =
+ new ReferenceWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
+
/**
* The interface used by the strategy to interact with the surrounding service.
*
@@ -166,6 +171,20 @@
}
@Override
+ public synchronized void suggestGnssTime(@NonNull GnssTimeSuggestion timeSuggestion) {
+ final TimestampedValue<Long> newUtcTime = timeSuggestion.getUtcTime();
+
+ if (!validateAutoSuggestionTime(newUtcTime, timeSuggestion)) {
+ return;
+ }
+
+ mLastGnssSuggestion.set(timeSuggestion);
+
+ String reason = "GNSS time suggestion received: suggestion=" + timeSuggestion;
+ doAutoTimeDetection(reason);
+ }
+
+ @Override
public synchronized boolean suggestManualTime(@NonNull ManualTimeSuggestion suggestion) {
final TimestampedValue<Long> newUtcTime = suggestion.getUtcTime();
@@ -280,6 +299,11 @@
mLastNetworkSuggestion.dump(ipw);
ipw.decreaseIndent(); // level 2
+ ipw.println("Gnss suggestion history:");
+ ipw.increaseIndent(); // level 2
+ mLastGnssSuggestion.dump(ipw);
+ ipw.decreaseIndent(); // level 2
+
ipw.decreaseIndent(); // level 1
ipw.flush();
}
@@ -386,6 +410,14 @@
+ ", networkSuggestion=" + networkSuggestion
+ ", detectionReason=" + detectionReason;
}
+ } else if (origin == ORIGIN_GNSS) {
+ GnssTimeSuggestion gnssTimeSuggestion = findLatestValidGnssSuggestion();
+ if (gnssTimeSuggestion != null) {
+ newUtcTime = gnssTimeSuggestion.getUtcTime();
+ cause = "Found good gnss suggestion."
+ + ", gnssTimeSuggestion=" + gnssTimeSuggestion
+ + ", detectionReason=" + detectionReason;
+ }
} else {
Slog.w(LOG_TAG, "Unknown or unsupported origin=" + origin
+ " in " + Arrays.toString(originPriorities)
@@ -527,6 +559,26 @@
return networkSuggestion;
}
+ /** Returns the latest, valid, gnss suggestion. Returns {@code null} if there isn't one. */
+ @GuardedBy("this")
+ @Nullable
+ private GnssTimeSuggestion findLatestValidGnssSuggestion() {
+ GnssTimeSuggestion gnssTimeSuggestion = mLastGnssSuggestion.get();
+ if (gnssTimeSuggestion == null) {
+ // No gnss suggestions received. This is normal if there's no gnss signal.
+ return null;
+ }
+
+ TimestampedValue<Long> utcTime = gnssTimeSuggestion.getUtcTime();
+ long elapsedRealTimeMillis = mCallback.elapsedRealtimeMillis();
+ if (!validateSuggestionUtcTime(elapsedRealTimeMillis, utcTime)) {
+ // The latest suggestion is not valid, usually due to its age.
+ return null;
+ }
+
+ return gnssTimeSuggestion;
+ }
+
@GuardedBy("this")
private boolean setSystemClockIfRequired(
@Origin int origin, @NonNull TimestampedValue<Long> time, @NonNull String cause) {
@@ -655,6 +707,16 @@
}
/**
+ * Returns the latest valid gnss suggestion. Not intended for general use: it is used during
+ * tests to check strategy behavior.
+ */
+ @VisibleForTesting
+ @Nullable
+ public synchronized GnssTimeSuggestion findLatestValidGnssSuggestionForTests() {
+ return findLatestValidGnssSuggestion();
+ }
+
+ /**
* A method used to inspect state during tests. Not intended for general use.
*/
@VisibleForTesting
@@ -672,6 +734,15 @@
return mLastNetworkSuggestion.get();
}
+ /**
+ * A method used to inspect state during tests. Not intended for general use.
+ */
+ @VisibleForTesting
+ @Nullable
+ public synchronized GnssTimeSuggestion getLatestGnssSuggestion() {
+ return mLastGnssSuggestion.get();
+ }
+
private static boolean validateSuggestionUtcTime(
long elapsedRealtimeMillis, TimestampedValue<Long> utcTime) {
long referenceTimeMillis = utcTime.getReferenceTimeMillis();
diff --git a/services/core/java/com/android/server/timezone/OWNERS b/services/core/java/com/android/server/timezone/OWNERS
index 09447a9..8f80897 100644
--- a/services/core/java/com/android/server/timezone/OWNERS
+++ b/services/core/java/com/android/server/timezone/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/core/java/com/android/server/timezonedetector/OWNERS b/services/core/java/com/android/server/timezonedetector/OWNERS
index 09447a9..8f80897 100644
--- a/services/core/java/com/android/server/timezonedetector/OWNERS
+++ b/services/core/java/com/android/server/timezonedetector/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 29bf374..ae9bd41 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -37,7 +37,6 @@
"java/android/net/util/NetworkConstants.java",
"java/android/net/IpMemoryStore.java",
"java/android/net/NetworkMonitorManager.java",
- "java/android/net/TcpKeepalivePacketData.java",
],
sdk_version: "module_current",
min_sdk_version: "30",
diff --git a/services/net/java/android/net/TcpKeepalivePacketData.java b/services/net/java/android/net/TcpKeepalivePacketData.java
deleted file mode 100644
index 4875c7c..0000000
--- a/services/net/java/android/net/TcpKeepalivePacketData.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-package android.net;
-
-import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.system.OsConstants;
-
-import com.android.net.module.util.IpUtils;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.Objects;
-
-/**
- * Represents the actual tcp keep alive packets which will be used for hardware offload.
- * @hide
- */
-public class TcpKeepalivePacketData extends KeepalivePacketData implements Parcelable {
- private static final String TAG = "TcpKeepalivePacketData";
-
- /** TCP sequence number. */
- public final int tcpSeq;
-
- /** TCP ACK number. */
- public final int tcpAck;
-
- /** TCP RCV window. */
- public final int tcpWnd;
-
- /** TCP RCV window scale. */
- public final int tcpWndScale;
-
- /** IP TOS. */
- public final int ipTos;
-
- /** IP TTL. */
- public final int ipTtl;
-
- private static final int IPV4_HEADER_LENGTH = 20;
- private static final int IPV6_HEADER_LENGTH = 40;
- private static final int TCP_HEADER_LENGTH = 20;
-
- // This should only be constructed via static factory methods, such as
- // tcpKeepalivePacket.
- private TcpKeepalivePacketData(final TcpKeepalivePacketDataParcelable tcpDetails,
- final byte[] data) throws InvalidPacketException, UnknownHostException {
- super(InetAddress.getByAddress(tcpDetails.srcAddress), tcpDetails.srcPort,
- InetAddress.getByAddress(tcpDetails.dstAddress), tcpDetails.dstPort, data);
- tcpSeq = tcpDetails.seq;
- tcpAck = tcpDetails.ack;
- // In the packet, the window is shifted right by the window scale.
- tcpWnd = tcpDetails.rcvWnd;
- tcpWndScale = tcpDetails.rcvWndScale;
- ipTos = tcpDetails.tos;
- ipTtl = tcpDetails.ttl;
- }
-
- private TcpKeepalivePacketData(final InetAddress srcAddress, int srcPort,
- final InetAddress dstAddress, int dstPort, final byte[] data, int tcpSeq,
- int tcpAck, int tcpWnd, int tcpWndScale, int ipTos, int ipTtl)
- throws InvalidPacketException {
- super(srcAddress, srcPort, dstAddress, dstPort, data);
- this.tcpSeq = tcpSeq;
- this.tcpAck = tcpAck;
- this.tcpWnd = tcpWnd;
- this.tcpWndScale = tcpWndScale;
- this.ipTos = ipTos;
- this.ipTtl = ipTtl;
- }
-
- /**
- * Factory method to create tcp keepalive packet structure.
- */
- public static TcpKeepalivePacketData tcpKeepalivePacket(
- TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException {
- final byte[] packet;
- try {
- if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null)
- && (tcpDetails.srcAddress.length == 4 /* V4 IP length */)
- && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) {
- packet = buildV4Packet(tcpDetails);
- } else {
- // TODO: support ipv6
- throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
- }
- return new TcpKeepalivePacketData(tcpDetails, packet);
- } catch (UnknownHostException e) {
- throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
- }
-
- }
-
- /**
- * Build ipv4 tcp keepalive packet, not including the link-layer header.
- */
- // TODO : if this code is ever moved to the network stack, factorize constants with the ones
- // over there.
- private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) {
- final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
- ByteBuffer buf = ByteBuffer.allocate(length);
- buf.order(ByteOrder.BIG_ENDIAN);
- buf.put((byte) 0x45); // IP version and IHL
- buf.put((byte) tcpDetails.tos); // TOS
- buf.putShort((short) length);
- buf.putInt(0x00004000); // ID, flags=DF, offset
- buf.put((byte) tcpDetails.ttl); // TTL
- buf.put((byte) OsConstants.IPPROTO_TCP);
- final int ipChecksumOffset = buf.position();
- buf.putShort((short) 0); // IP checksum
- buf.put(tcpDetails.srcAddress);
- buf.put(tcpDetails.dstAddress);
- buf.putShort((short) tcpDetails.srcPort);
- buf.putShort((short) tcpDetails.dstPort);
- buf.putInt(tcpDetails.seq); // Sequence Number
- buf.putInt(tcpDetails.ack); // ACK
- buf.putShort((short) 0x5010); // TCP length=5, flags=ACK
- buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size
- final int tcpChecksumOffset = buf.position();
- buf.putShort((short) 0); // TCP checksum
- // URG is not set therefore the urgent pointer is zero.
- buf.putShort((short) 0); // Urgent pointer
-
- buf.putShort(ipChecksumOffset, IpUtils.ipChecksum(buf, 0));
- buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum(
- buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH));
-
- return buf.array();
- }
-
- // TODO: add buildV6Packet.
-
- @Override
- public boolean equals(@Nullable final Object o) {
- if (!(o instanceof TcpKeepalivePacketData)) return false;
- final TcpKeepalivePacketData other = (TcpKeepalivePacketData) o;
- final InetAddress srcAddress = getSrcAddress();
- final InetAddress dstAddress = getDstAddress();
- return srcAddress.equals(other.getSrcAddress())
- && dstAddress.equals(other.getDstAddress())
- && getSrcPort() == other.getSrcPort()
- && getDstPort() == other.getDstPort()
- && this.tcpAck == other.tcpAck
- && this.tcpSeq == other.tcpSeq
- && this.tcpWnd == other.tcpWnd
- && this.tcpWndScale == other.tcpWndScale
- && this.ipTos == other.ipTos
- && this.ipTtl == other.ipTtl;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getSrcAddress(), getDstAddress(), getSrcPort(), getDstPort(),
- tcpAck, tcpSeq, tcpWnd, tcpWndScale, ipTos, ipTtl);
- }
-
- /**
- * Parcelable Implementation.
- * Note that this object implements parcelable (and needs to keep doing this as it inherits
- * from a class that does), but should usually be parceled as a stable parcelable using
- * the toStableParcelable() and fromStableParcelable() methods.
- */
- public int describeContents() {
- return 0;
- }
-
- /** Write to parcel. */
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(getSrcAddress().getHostAddress());
- out.writeString(getDstAddress().getHostAddress());
- out.writeInt(getSrcPort());
- out.writeInt(getDstPort());
- out.writeByteArray(getPacket());
- out.writeInt(tcpSeq);
- out.writeInt(tcpAck);
- out.writeInt(tcpWnd);
- out.writeInt(tcpWndScale);
- out.writeInt(ipTos);
- out.writeInt(ipTtl);
- }
-
- private static TcpKeepalivePacketData readFromParcel(Parcel in) throws InvalidPacketException {
- InetAddress srcAddress = InetAddresses.parseNumericAddress(in.readString());
- InetAddress dstAddress = InetAddresses.parseNumericAddress(in.readString());
- int srcPort = in.readInt();
- int dstPort = in.readInt();
- byte[] packet = in.createByteArray();
- int tcpSeq = in.readInt();
- int tcpAck = in.readInt();
- int tcpWnd = in.readInt();
- int tcpWndScale = in.readInt();
- int ipTos = in.readInt();
- int ipTtl = in.readInt();
- return new TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, packet, tcpSeq,
- tcpAck, tcpWnd, tcpWndScale, ipTos, ipTtl);
- }
-
- /** Parcelable Creator. */
- public static final @NonNull Parcelable.Creator<TcpKeepalivePacketData> CREATOR =
- new Parcelable.Creator<TcpKeepalivePacketData>() {
- public TcpKeepalivePacketData createFromParcel(Parcel in) {
- try {
- return readFromParcel(in);
- } catch (InvalidPacketException e) {
- throw new IllegalArgumentException(
- "Invalid NAT-T keepalive data: " + e.getError());
- }
- }
-
- public TcpKeepalivePacketData[] newArray(int size) {
- return new TcpKeepalivePacketData[size];
- }
- };
-
- /**
- * Convert this TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable.
- */
- @NonNull
- public TcpKeepalivePacketDataParcelable toStableParcelable() {
- final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
- final InetAddress srcAddress = getSrcAddress();
- final InetAddress dstAddress = getDstAddress();
- parcel.srcAddress = srcAddress.getAddress();
- parcel.srcPort = getSrcPort();
- parcel.dstAddress = dstAddress.getAddress();
- parcel.dstPort = getDstPort();
- parcel.seq = tcpSeq;
- parcel.ack = tcpAck;
- parcel.rcvWnd = tcpWnd;
- parcel.rcvWndScale = tcpWndScale;
- parcel.tos = ipTos;
- parcel.ttl = ipTtl;
- return parcel;
- }
-
- @Override
- public String toString() {
- return "saddr: " + getSrcAddress()
- + " daddr: " + getDstAddress()
- + " sport: " + getSrcPort()
- + " dport: " + getDstPort()
- + " seq: " + tcpSeq
- + " ack: " + tcpAck
- + " wnd: " + tcpWnd
- + " wndScale: " + tcpWndScale
- + " tos: " + ipTos
- + " ttl: " + ipTtl;
- }
-}
diff --git a/services/net/java/android/net/ip/IpClientManager.java b/services/net/java/android/net/ip/IpClientManager.java
index db464e7..274b6dc 100644
--- a/services/net/java/android/net/ip/IpClientManager.java
+++ b/services/net/java/android/net/ip/IpClientManager.java
@@ -21,6 +21,7 @@
import android.net.NattKeepalivePacketData;
import android.net.ProxyInfo;
import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketDataParcelable;
import android.net.shared.Layer2Information;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.KeepalivePacketDataUtil;
@@ -215,9 +216,20 @@
* Add a TCP keepalive packet filter before setting up keepalive offload.
*/
public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketData pkt) {
+ return addKeepalivePacketFilter(slot, KeepalivePacketDataUtil.toStableParcelable(pkt));
+ }
+
+ /**
+ * Add a TCP keepalive packet filter before setting up keepalive offload.
+ * @deprecated This method is for use on pre-S platforms where TcpKeepalivePacketData is not
+ * system API. On newer platforms use
+ * addKeepalivePacketFilter(int, TcpKeepalivePacketData) instead.
+ */
+ @Deprecated
+ public boolean addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
final long token = Binder.clearCallingIdentity();
try {
- mIpClient.addKeepalivePacketFilter(slot, pkt.toStableParcelable());
+ mIpClient.addKeepalivePacketFilter(slot, pkt);
return true;
} catch (RemoteException e) {
log("Error adding Keepalive Packet Filter ", e);
diff --git a/services/net/java/android/net/util/KeepalivePacketDataUtil.java b/services/net/java/android/net/util/KeepalivePacketDataUtil.java
index 4466ea0..6e539bb 100644
--- a/services/net/java/android/net/util/KeepalivePacketDataUtil.java
+++ b/services/net/java/android/net/util/KeepalivePacketDataUtil.java
@@ -16,20 +16,47 @@
package android.net.util;
+import static android.net.SocketKeepalive.ERROR_INVALID_IP_ADDRESS;
+
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.InvalidPacketException;
+import android.net.KeepalivePacketData;
import android.net.NattKeepalivePacketData;
import android.net.NattKeepalivePacketDataParcelable;
+import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketDataParcelable;
+import android.os.Build;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.net.module.util.IpUtils;
import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
-/** @hide */
+/**
+ * Utility class to convert to/from keepalive data parcelables.
+ *
+ * TODO: move to networkstack-client library when it is moved to frameworks/libs/net.
+ * This class cannot go into other shared libraries as it depends on NetworkStack AIDLs.
+ * @hide
+ */
public final class KeepalivePacketDataUtil {
- /**
- * Convert this NattKeepalivePacketData to a NattKeepalivePacketDataParcelable.
+ private static final int IPV4_HEADER_LENGTH = 20;
+ private static final int IPV6_HEADER_LENGTH = 40;
+ private static final int TCP_HEADER_LENGTH = 20;
+
+ private static final String TAG = KeepalivePacketDataUtil.class.getSimpleName();
+
+ /**
+ * Convert a NattKeepalivePacketData to a NattKeepalivePacketDataParcelable.
*/
@NonNull
public static NattKeepalivePacketDataParcelable toStableParcelable(
- NattKeepalivePacketData pkt) {
+ @NonNull NattKeepalivePacketData pkt) {
final NattKeepalivePacketDataParcelable parcel = new NattKeepalivePacketDataParcelable();
final InetAddress srcAddress = pkt.getSrcAddress();
final InetAddress dstAddress = pkt.getDstAddress();
@@ -39,4 +66,158 @@
parcel.dstPort = pkt.getDstPort();
return parcel;
}
+
+ /**
+ * Convert a TcpKeepalivePacketData to a TcpKeepalivePacketDataParcelable.
+ */
+ @NonNull
+ public static TcpKeepalivePacketDataParcelable toStableParcelable(
+ @NonNull TcpKeepalivePacketData pkt) {
+ final TcpKeepalivePacketDataParcelable parcel = new TcpKeepalivePacketDataParcelable();
+ final InetAddress srcAddress = pkt.getSrcAddress();
+ final InetAddress dstAddress = pkt.getDstAddress();
+ parcel.srcAddress = srcAddress.getAddress();
+ parcel.srcPort = pkt.getSrcPort();
+ parcel.dstAddress = dstAddress.getAddress();
+ parcel.dstPort = pkt.getDstPort();
+ parcel.seq = pkt.tcpSeq;
+ parcel.ack = pkt.tcpAck;
+ parcel.rcvWnd = pkt.tcpWindow;
+ parcel.rcvWndScale = pkt.tcpWindowScale;
+ parcel.tos = pkt.ipTos;
+ parcel.ttl = pkt.ipTtl;
+ return parcel;
+ }
+
+ /**
+ * Factory method to create tcp keepalive packet structure.
+ * @hide
+ */
+ public static TcpKeepalivePacketData fromStableParcelable(
+ TcpKeepalivePacketDataParcelable tcpDetails) throws InvalidPacketException {
+ final byte[] packet;
+ try {
+ if ((tcpDetails.srcAddress != null) && (tcpDetails.dstAddress != null)
+ && (tcpDetails.srcAddress.length == 4 /* V4 IP length */)
+ && (tcpDetails.dstAddress.length == 4 /* V4 IP length */)) {
+ packet = buildV4Packet(tcpDetails);
+ } else {
+ // TODO: support ipv6
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+ }
+ return new TcpKeepalivePacketData(
+ InetAddress.getByAddress(tcpDetails.srcAddress),
+ tcpDetails.srcPort,
+ InetAddress.getByAddress(tcpDetails.dstAddress),
+ tcpDetails.dstPort,
+ packet,
+ tcpDetails.seq, tcpDetails.ack, tcpDetails.rcvWnd, tcpDetails.rcvWndScale,
+ tcpDetails.tos, tcpDetails.ttl);
+ } catch (UnknownHostException e) {
+ throw new InvalidPacketException(ERROR_INVALID_IP_ADDRESS);
+ }
+
+ }
+
+ /**
+ * Build ipv4 tcp keepalive packet, not including the link-layer header.
+ */
+ // TODO : if this code is ever moved to the network stack, factorize constants with the ones
+ // over there.
+ private static byte[] buildV4Packet(TcpKeepalivePacketDataParcelable tcpDetails) {
+ final int length = IPV4_HEADER_LENGTH + TCP_HEADER_LENGTH;
+ ByteBuffer buf = ByteBuffer.allocate(length);
+ buf.order(ByteOrder.BIG_ENDIAN);
+ buf.put((byte) 0x45); // IP version and IHL
+ buf.put((byte) tcpDetails.tos); // TOS
+ buf.putShort((short) length);
+ buf.putInt(0x00004000); // ID, flags=DF, offset
+ buf.put((byte) tcpDetails.ttl); // TTL
+ buf.put((byte) OsConstants.IPPROTO_TCP);
+ final int ipChecksumOffset = buf.position();
+ buf.putShort((short) 0); // IP checksum
+ buf.put(tcpDetails.srcAddress);
+ buf.put(tcpDetails.dstAddress);
+ buf.putShort((short) tcpDetails.srcPort);
+ buf.putShort((short) tcpDetails.dstPort);
+ buf.putInt(tcpDetails.seq); // Sequence Number
+ buf.putInt(tcpDetails.ack); // ACK
+ buf.putShort((short) 0x5010); // TCP length=5, flags=ACK
+ buf.putShort((short) (tcpDetails.rcvWnd >> tcpDetails.rcvWndScale)); // Window size
+ final int tcpChecksumOffset = buf.position();
+ buf.putShort((short) 0); // TCP checksum
+ // URG is not set therefore the urgent pointer is zero.
+ buf.putShort((short) 0); // Urgent pointer
+
+ buf.putShort(ipChecksumOffset, com.android.net.module.util.IpUtils.ipChecksum(buf, 0));
+ buf.putShort(tcpChecksumOffset, IpUtils.tcpChecksum(
+ buf, 0, IPV4_HEADER_LENGTH, TCP_HEADER_LENGTH));
+
+ return buf.array();
+ }
+
+ // TODO: add buildV6Packet.
+
+ /**
+ * Get a {@link TcpKeepalivePacketDataParcelable} from {@link KeepalivePacketData}, if the
+ * generic class actually contains TCP keepalive data.
+ *
+ * @deprecated This method is used on R platforms where android.net.TcpKeepalivePacketData was
+ * not yet system API. Newer platforms should use android.net.TcpKeepalivePacketData directly.
+ *
+ * @param data A {@link KeepalivePacketData} that may contain TCP keepalive data.
+ * @return A parcelable containing TCP keepalive data, or null if the input data does not
+ * contain TCP keepalive data.
+ */
+ @Deprecated
+ @SuppressWarnings("AndroidFrameworkCompatChange") // API version check used to Log.wtf
+ @Nullable
+ public static TcpKeepalivePacketDataParcelable parseTcpKeepalivePacketData(
+ @Nullable KeepalivePacketData data) {
+ if (data == null) return null;
+
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
+ Log.wtf(TAG, "parseTcpKeepalivePacketData should not be used after R, use "
+ + "TcpKeepalivePacketData instead.");
+ }
+
+ // Reconstruct TcpKeepalivePacketData from the packet contained in KeepalivePacketData
+ final ByteBuffer buffer = ByteBuffer.wrap(data.getPacket());
+ buffer.order(ByteOrder.BIG_ENDIAN);
+
+ // Most of the fields are accessible from the KeepalivePacketData superclass: instead of
+ // using Struct to parse everything, just extract the extra fields necessary for
+ // TcpKeepalivePacketData.
+ final int tcpSeq;
+ final int tcpAck;
+ final int wndSize;
+ final int ipTos;
+ final int ttl;
+ try {
+ // This only support IPv4, because TcpKeepalivePacketData only supports IPv4 for R and
+ // below, and this method should not be used on newer platforms.
+ tcpSeq = buffer.getInt(IPV4_HEADER_LENGTH + 4);
+ tcpAck = buffer.getInt(IPV4_HEADER_LENGTH + 8);
+ wndSize = buffer.getShort(IPV4_HEADER_LENGTH + 14);
+ ipTos = buffer.get(1);
+ ttl = buffer.get(8);
+ } catch (IndexOutOfBoundsException e) {
+ return null;
+ }
+
+ final TcpKeepalivePacketDataParcelable p = new TcpKeepalivePacketDataParcelable();
+ p.srcAddress = data.getSrcAddress().getAddress();
+ p.srcPort = data.getSrcPort();
+ p.dstAddress = data.getDstAddress().getAddress();
+ p.dstPort = data.getDstPort();
+ p.seq = tcpSeq;
+ p.ack = tcpAck;
+ // TcpKeepalivePacketData could actually use non-zero wndScale, but this does not affect
+ // actual functionality as generated packets will be the same (no wndScale option added)
+ p.rcvWnd = wndSize;
+ p.rcvWndScale = 0;
+ p.tos = ipTos;
+ p.ttl = ttl;
+ return p;
+ }
}
diff --git a/services/robotests/src/com/android/server/location/OWNERS b/services/robotests/src/com/android/server/location/OWNERS
new file mode 100644
index 0000000..696a0c2
--- /dev/null
+++ b/services/robotests/src/com/android/server/location/OWNERS
@@ -0,0 +1 @@
+file:/location/java/android/location/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
index c4d1211..98d6452 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/RebootEscrowManagerTests.java
@@ -95,13 +95,24 @@
static class MockInjector extends RebootEscrowManager.Injector {
private final IRebootEscrow mRebootEscrow;
+ private final RebootEscrowProviderInterface mRebootEscrowProvider;
private final UserManager mUserManager;
private final MockableRebootEscrowInjected mInjected;
- MockInjector(Context context, UserManager userManager, IRebootEscrow rebootEscrow,
+ MockInjector(Context context, UserManager userManager,
+ IRebootEscrow rebootEscrow,
MockableRebootEscrowInjected injected) {
super(context);
mRebootEscrow = rebootEscrow;
+
+ RebootEscrowProviderHalImpl.Injector halInjector =
+ new RebootEscrowProviderHalImpl.Injector() {
+ @Override
+ public IRebootEscrow getRebootEscrow() {
+ return mRebootEscrow;
+ }
+ };
+ mRebootEscrowProvider = new RebootEscrowProviderHalImpl(halInjector);
mUserManager = userManager;
mInjected = injected;
}
@@ -112,8 +123,8 @@
}
@Override
- public IRebootEscrow getRebootEscrow() {
- return mRebootEscrow;
+ public RebootEscrowProviderInterface getRebootEscrowProvider() {
+ return mRebootEscrowProvider;
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/recoverysystem/OWNERS b/services/tests/servicestests/src/com/android/server/recoverysystem/OWNERS
new file mode 100644
index 0000000..3880038
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/recoverysystem/OWNERS
@@ -0,0 +1 @@
+include /services/core/java/com/android/server/recoverysystem/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
index 09447a9..8f80897 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timedetector/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
index 22addf9..f0b1be5 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorServiceTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -172,6 +173,36 @@
mStubbedTimeDetectorStrategy.verifySuggestNetworkTimeCalled(NetworkTimeSuggestion);
}
+ @Test(expected = SecurityException.class)
+ public void testSuggestGnssTime_withoutPermission() {
+ doThrow(new SecurityException("Mock"))
+ .when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+ GnssTimeSuggestion gnssTimeSuggestion = createGnssTimeSuggestion();
+
+ try {
+ mTimeDetectorService.suggestGnssTime(gnssTimeSuggestion);
+ fail();
+ } finally {
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+ }
+ }
+
+ @Test
+ public void testSuggestGnssTime() throws Exception {
+ doNothing().when(mMockContext).enforceCallingOrSelfPermission(anyString(), any());
+
+ GnssTimeSuggestion gnssTimeSuggestion = createGnssTimeSuggestion();
+ mTimeDetectorService.suggestGnssTime(gnssTimeSuggestion);
+ mTestHandler.assertTotalMessagesEnqueued(1);
+
+ verify(mMockContext).enforceCallingOrSelfPermission(
+ eq(android.Manifest.permission.SET_TIME), anyString());
+
+ mTestHandler.waitForMessagesToBeProcessed();
+ mStubbedTimeDetectorStrategy.verifySuggestGnssTimeCalled(gnssTimeSuggestion);
+ }
+
@Test
public void testDump() {
when(mMockContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP))
@@ -216,12 +247,18 @@
return new NetworkTimeSuggestion(timeValue);
}
+ private static GnssTimeSuggestion createGnssTimeSuggestion() {
+ TimestampedValue<Long> timeValue = new TimestampedValue<>(100L, 1_000_000L);
+ return new GnssTimeSuggestion(timeValue);
+ }
+
private static class StubbedTimeDetectorStrategy implements TimeDetectorStrategy {
// Call tracking.
private TelephonyTimeSuggestion mLastTelephonySuggestion;
private ManualTimeSuggestion mLastManualSuggestion;
private NetworkTimeSuggestion mLastNetworkSuggestion;
+ private GnssTimeSuggestion mLastGnssSuggestion;
private boolean mHandleAutoTimeDetectionChangedCalled;
private boolean mDumpCalled;
@@ -242,6 +279,11 @@
}
@Override
+ public void suggestGnssTime(GnssTimeSuggestion timeSuggestion) {
+ mLastGnssSuggestion = timeSuggestion;
+ }
+
+ @Override
public void handleAutoTimeConfigChanged() {
mHandleAutoTimeDetectionChangedCalled = true;
}
@@ -255,6 +297,7 @@
mLastTelephonySuggestion = null;
mLastManualSuggestion = null;
mLastNetworkSuggestion = null;
+ mLastGnssSuggestion = null;
mHandleAutoTimeDetectionChangedCalled = false;
mDumpCalled = false;
}
@@ -271,6 +314,10 @@
assertEquals(expectedSuggestion, mLastNetworkSuggestion);
}
+ void verifySuggestGnssTimeCalled(GnssTimeSuggestion expectedSuggestion) {
+ assertEquals(expectedSuggestion, mLastGnssSuggestion);
+ }
+
void verifyHandleAutoTimeDetectionChangedCalled() {
assertTrue(mHandleAutoTimeDetectionChangedCalled);
}
diff --git a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
index 21396fd..b1adb0b 100644
--- a/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timedetector/TimeDetectorStrategyImplTest.java
@@ -16,6 +16,7 @@
package com.android.server.timedetector;
+import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_GNSS;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_NETWORK;
import static com.android.server.timedetector.TimeDetectorStrategy.ORIGIN_TELEPHONY;
@@ -25,6 +26,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.timedetector.GnssTimeSuggestion;
import android.app.timedetector.ManualTimeSuggestion;
import android.app.timedetector.NetworkTimeSuggestion;
import android.app.timedetector.TelephonyTimeSuggestion;
@@ -569,7 +571,53 @@
}
@Test
- public void highPrioritySuggestionsShouldBeatLowerPrioritySuggestions() {
+ public void testSuggestGnssTime_autoTimeEnabled() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_GNSS)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ GnssTimeSuggestion timeSuggestion =
+ mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateTimePassing();
+
+ long expectedSystemClockMillis =
+ mScript.calculateTimeInMillisForNow(timeSuggestion.getUtcTime());
+ mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(expectedSystemClockMillis);
+ }
+
+ @Test
+ public void testSuggestGnssTime_autoTimeDisabled() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_GNSS)
+ .pokeAutoTimeDetectionEnabled(false);
+
+ GnssTimeSuggestion timeSuggestion =
+ mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateTimePassing()
+ .simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void gnssTimeSuggestion_ignoredWhenReferencedTimeIsInThePast() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoOriginPriorities(ORIGIN_GNSS)
+ .pokeAutoTimeDetectionEnabled(true);
+
+ Instant suggestedTime = TIME_LOWER_BOUND.minus(Duration.ofDays(1));
+ GnssTimeSuggestion timeSuggestion = mScript
+ .generateGnssTimeSuggestion(suggestedTime);
+
+ mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking()
+ .assertLatestGnssSuggestion(null);
+ }
+
+ @Test
+ public void highPrioritySuggestionsBeatLowerPrioritySuggestions_telephonyNetworkOrigins() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
.pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
@@ -672,22 +720,130 @@
}
@Test
+ public void highPrioritySuggestionsBeatLowerPrioritySuggestions_networkGnssOrigins() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK, ORIGIN_GNSS);
+
+ // Three obviously different times that could not be mistaken for each other.
+ Instant gnssTime1 = ARBITRARY_TEST_TIME;
+ Instant gnssTime2 = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+ Instant networkTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
+ // A small increment used to simulate the passage of time, but not enough to interfere with
+ // macro-level time changes associated with suggestion age.
+ final long smallTimeIncrementMillis = 101;
+
+ // A gnss suggestion is made. It should be used because there is no network suggestion.
+ GnssTimeSuggestion gnssTimeSuggestion1 =
+ mScript.generateGnssTimeSuggestion(gnssTime1);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulateGnssTimeSuggestion(gnssTimeSuggestion1)
+ .verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(gnssTimeSuggestion1.getUtcTime()));
+
+ // Check internal state.
+ mScript.assertLatestNetworkSuggestion(null)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion1);
+ assertEquals(gnssTimeSuggestion1, mScript.peekLatestValidGnssSuggestion());
+ assertNull("No network suggestions were made:", mScript.peekLatestValidNetworkSuggestion());
+
+ // Simulate a little time passing.
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now a network suggestion is made. Network suggestions are prioritized over gnss
+ // suggestions so it should "win".
+ NetworkTimeSuggestion networkTimeSuggestion =
+ mScript.generateNetworkTimeSuggestion(networkTime);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(networkTimeSuggestion.getUtcTime()));
+
+ // Check internal state.
+ mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion1);
+ assertEquals(gnssTimeSuggestion1, mScript.peekLatestValidGnssSuggestion());
+ assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+
+ // Simulate some significant time passing: half the time allowed before a time signal
+ // becomes "too old to use".
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Now another gnss suggestion is made. Network suggestions are prioritized over
+ // gnss suggestions so the latest network suggestion should still "win".
+ GnssTimeSuggestion gnssTimeSuggestion2 =
+ mScript.generateGnssTimeSuggestion(gnssTime2);
+ mScript.simulateTimePassing(smallTimeIncrementMillis)
+ .simulateGnssTimeSuggestion(gnssTimeSuggestion2)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Check internal state.
+ mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion2);
+ assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
+ assertEquals(networkTimeSuggestion, mScript.peekLatestValidNetworkSuggestion());
+
+ // Simulate some significant time passing: half the time allowed before a time signal
+ // becomes "too old to use". This should mean that telephonyTimeSuggestion is now too old to
+ // be used but networkTimeSuggestion2 is not.
+ mScript.simulateTimePassing(TimeDetectorStrategyImpl.MAX_UTC_TIME_AGE_MILLIS / 2);
+
+ // NOTE: The TimeDetectorStrategyImpl doesn't set an alarm for the point when the last
+ // suggestion it used becomes too old: it requires a new suggestion or an auto-time toggle
+ // to re-run the detection logic. This may change in future but until then we rely on a
+ // steady stream of suggestions to re-evaluate.
+ mScript.verifySystemClockWasNotSetAndResetCallTracking();
+
+ // Check internal state.
+ mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion2);
+ assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
+ assertNull(
+ "Network suggestion should be expired:",
+ mScript.peekLatestValidNetworkSuggestion());
+
+ // Toggle auto-time off and on to force the detection logic to run.
+ mScript.simulateAutoTimeDetectionToggle()
+ .simulateTimePassing(smallTimeIncrementMillis)
+ .simulateAutoTimeDetectionToggle();
+
+ // Verify the latest gnss time now wins.
+ mScript.verifySystemClockWasSetAndResetCallTracking(
+ mScript.calculateTimeInMillisForNow(gnssTimeSuggestion2.getUtcTime()));
+
+ // Check internal state.
+ mScript.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion2);
+ assertEquals(gnssTimeSuggestion2, mScript.peekLatestValidGnssSuggestion());
+ assertNull(
+ "Network suggestion should still be expired:",
+ mScript.peekLatestValidNetworkSuggestion());
+ }
+
+ @Test
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_lowerPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_GNSS);
Instant networkTime = ARBITRARY_TEST_TIME;
- Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+ Instant gnssTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+ Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
NetworkTimeSuggestion networkTimeSuggestion =
mScript.generateNetworkTimeSuggestion(networkTime);
+ GnssTimeSuggestion gnssTimeSuggestion =
+ mScript.generateGnssTimeSuggestion(gnssTime);
TelephonyTimeSuggestion telephonyTimeSuggestion =
mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
mScript.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .simulateGnssTimeSuggestion(gnssTimeSuggestion)
.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion)
.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
}
@@ -696,20 +852,25 @@
public void whenAllTimeSuggestionsAreAvailable_higherPriorityWins_higherPriorityComesFirst() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
- .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK);
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_GNSS);
Instant networkTime = ARBITRARY_TEST_TIME;
Instant telephonyTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(30));
+ Instant gnssTime = ARBITRARY_TEST_TIME.plus(Duration.ofDays(60));
NetworkTimeSuggestion networkTimeSuggestion =
mScript.generateNetworkTimeSuggestion(networkTime);
TelephonyTimeSuggestion telephonyTimeSuggestion =
mScript.generateTelephonyTimeSuggestion(ARBITRARY_SLOT_INDEX, telephonyTime);
+ GnssTimeSuggestion gnssTimeSuggestion =
+ mScript.generateGnssTimeSuggestion(gnssTime);
mScript.simulateTelephonyTimeSuggestion(telephonyTimeSuggestion)
.simulateNetworkTimeSuggestion(networkTimeSuggestion)
+ .simulateGnssTimeSuggestion(gnssTimeSuggestion)
.assertLatestNetworkSuggestion(networkTimeSuggestion)
.assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, telephonyTimeSuggestion)
+ .assertLatestGnssSuggestion(gnssTimeSuggestion)
.verifySystemClockWasSetAndResetCallTracking(telephonyTime.toEpochMilli());
}
@@ -728,7 +889,37 @@
}
@Test
- public void suggestionsFromSourceNotListedInPrioritiesList_areIgnored() {
+ public void whenHigherPrioritySuggestionsAreNotAvailable_fallbacksToNext() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY, ORIGIN_NETWORK, ORIGIN_GNSS);
+
+ GnssTimeSuggestion timeSuggestion =
+ mScript.generateGnssTimeSuggestion(ARBITRARY_TEST_TIME);
+
+ mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ .assertLatestGnssSuggestion(timeSuggestion)
+ .verifySystemClockWasSetAndResetCallTracking(ARBITRARY_TEST_TIME.toEpochMilli());
+ }
+
+ @Test
+ public void suggestionsFromTelephonyOriginNotInPriorityList_areIgnored() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_NETWORK);
+
+ int slotIndex = ARBITRARY_SLOT_INDEX;
+ Instant testTime = ARBITRARY_TEST_TIME;
+ TelephonyTimeSuggestion timeSuggestion =
+ mScript.generateTelephonyTimeSuggestion(slotIndex, testTime);
+
+ mScript.simulateTelephonyTimeSuggestion(timeSuggestion)
+ .assertLatestTelephonySuggestion(ARBITRARY_SLOT_INDEX, timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
+ public void suggestionsFromNetworkOriginNotInPriorityList_areIgnored() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(true)
.pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
@@ -742,6 +933,20 @@
}
@Test
+ public void suggestionsFromGnssOriginNotInPriorityList_areIgnored() {
+ mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
+ .pokeAutoTimeDetectionEnabled(true)
+ .pokeAutoOriginPriorities(ORIGIN_TELEPHONY);
+
+ GnssTimeSuggestion timeSuggestion = mScript.generateGnssTimeSuggestion(
+ ARBITRARY_TEST_TIME);
+
+ mScript.simulateGnssTimeSuggestion(timeSuggestion)
+ .assertLatestGnssSuggestion(timeSuggestion)
+ .verifySystemClockWasNotSetAndResetCallTracking();
+ }
+
+ @Test
public void autoOriginPrioritiesList_doesNotAffectManualSuggestion() {
mScript.pokeFakeClocks(ARBITRARY_CLOCK_INITIALIZATION_INFO)
.pokeAutoTimeDetectionEnabled(false)
@@ -945,6 +1150,11 @@
return this;
}
+ Script simulateGnssTimeSuggestion(GnssTimeSuggestion timeSuggestion) {
+ mTimeDetectorStrategy.suggestGnssTime(timeSuggestion);
+ return this;
+ }
+
Script simulateAutoTimeDetectionToggle() {
mFakeCallback.simulateAutoTimeZoneDetectionToggle();
mTimeDetectorStrategy.handleAutoTimeConfigChanged();
@@ -995,6 +1205,14 @@
}
/**
+ * White box test info: Asserts the latest gnss suggestion is as expected.
+ */
+ Script assertLatestGnssSuggestion(GnssTimeSuggestion expected) {
+ assertEquals(expected, mTimeDetectorStrategy.getLatestGnssSuggestion());
+ return this;
+ }
+
+ /**
* White box test info: Returns the telephony suggestion that would be used, if any, given
* the current elapsed real time clock and regardless of origin prioritization.
*/
@@ -1011,6 +1229,14 @@
}
/**
+ * White box test info: Returns the gnss suggestion that would be used, if any, given the
+ * current elapsed real time clock and regardless of origin prioritization.
+ */
+ GnssTimeSuggestion peekLatestValidGnssSuggestion() {
+ return mTimeDetectorStrategy.findLatestValidGnssSuggestionForTests();
+ }
+
+ /**
* Generates a ManualTimeSuggestion using the current elapsed realtime clock for the
* reference time.
*/
@@ -1057,6 +1283,18 @@
}
/**
+ * Generates a GnssTimeSuggestion using the current elapsed realtime clock for the
+ * reference time.
+ */
+ GnssTimeSuggestion generateGnssTimeSuggestion(Instant suggestedTime) {
+ TimestampedValue<Long> utcTime =
+ new TimestampedValue<>(
+ mFakeCallback.peekElapsedRealtimeMillis(),
+ suggestedTime.toEpochMilli());
+ return new GnssTimeSuggestion(utcTime);
+ }
+
+ /**
* Calculates what the supplied time would be when adjusted for the movement of the fake
* elapsed realtime clock.
*/
diff --git a/services/tests/servicestests/src/com/android/server/timezone/OWNERS b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
index 09447a9..8f80897 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timezone/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
index 09447a9..8f80897 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/OWNERS
@@ -1 +1,3 @@
-include /core/java/android/app/timezone/OWNERS
+# Bug component: 847766
+mingaleev@google.com
+include /core/java/android/app/timedetector/OWNERS
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS
new file mode 100644
index 0000000..e5d0370
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/OWNERS
@@ -0,0 +1,2 @@
+ytai@google.com
+elaurent@google.com
diff --git a/telephony/java/android/telephony/DataFailCause.java b/telephony/java/android/telephony/DataFailCause.java
index 8b7a243..d502da9 100644
--- a/telephony/java/android/telephony/DataFailCause.java
+++ b/telephony/java/android/telephony/DataFailCause.java
@@ -916,6 +916,84 @@
/** System preference change back to SRAT during handoff */
public static final int HANDOFF_PREFERENCE_CHANGED = 0x8CB;
+ //IKE error notifications message as specified in 3GPP TS 24.302 (Section 8.1.2.2).
+
+ /** The PDN connection corresponding to the requested APN has been rejected. */
+ public static final int IWLAN_PDN_CONNECTION_REJECTION = 0x2000;
+ /**
+ * The PDN connection has been rejected. No additional PDN connections can be established
+ * for the UE due to the network policies or capabilities.
+ */
+ public static final int IWLAN_MAX_CONNECTION_REACHED = 0x2001;
+ /**
+ * The PDN connection has been rejected due to a semantic error in TFT operation.
+ */
+ public static final int IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 0x2031;
+ /**
+ * The PDN connection has been rejected due to a syntactic error in TFT operation.
+ */
+ public static final int IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION = 0x2032;
+ /**
+ * The PDN connection has been rejected due to sematic errors in the packet filter.
+ */
+ public static final int IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS = 0x2034;
+ /**
+ * The PDN connection has been rejected due to syntactic errors in the packet filter.
+ */
+ public static final int IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS = 0x2035;
+ /**
+ * No non-3GPP subscription is associated with the IMSI.
+ * The UE is not allowed to use non-3GPP access to EPC.
+ */
+ public static final int IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED = 0x2328;
+ /** The user identified by the IMSI is unknown. */
+ public static final int IWLAN_USER_UNKNOWN = 0x2329;
+ /**
+ * The requested APN is not included in the user's profile,
+ * and therefore is not authorized for that user.
+ */
+ public static final int IWLAN_NO_APN_SUBSCRIPTION = 0x232A;
+ /** The user is barred from using the non-3GPP access or the subscribed APN. */
+ public static final int IWLAN_AUTHORIZATION_REJECTED = 0x232B;
+ /** The Mobile Equipment used is not acceptable to the network */
+ public static final int IWLAN_ILLEGAL_ME = 0x232E;
+ /**
+ * The network has determined that the requested procedure cannot be completed successfully
+ * due to network failure.
+ */
+ public static final int IWLAN_NETWORK_FAILURE = 0x2904;
+ /** The access type is restricted to the user. */
+ public static final int IWLAN_RAT_TYPE_NOT_ALLOWED = 0x2AF9;
+ /** The network does not accept emergency PDN bringup request using an IMEI */
+ public static final int IWLAN_IMEI_NOT_ACCEPTED = 0x2AFD;
+ /**
+ * The ePDG performs PLMN filtering (based on roaming agreements) and rejects
+ * the request from the UE.
+ * The UE requests service in a PLMN where the UE is not allowed to operate.
+ */
+ public static final int IWLAN_PLMN_NOT_ALLOWED = 0x2B03;
+ /** The ePDG does not support un-authenticated IMSI based emergency PDN bringup **/
+ public static final int IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED = 0x2B2F;
+
+ // Device is unable to establish an IPSec tunnel with the ePDG for any reason
+ // e.g authentication fail or certificate validation or DNS Resolution and timeout failure.
+
+ /** IKE configuration error resulting in failure */
+ public static final int IWLAN_IKEV2_CONFIG_FAILURE = 0x4000;
+ /**
+ * Sent in the response to an IKE_AUTH message when, for some reason,
+ * the authentication failed.
+ */
+ public static final int IWLAN_IKEV2_AUTH_FAILURE = 0x4001;
+ /** IKE message timeout, tunnel setup failed due to no response from EPDG */
+ public static final int IWLAN_IKEV2_MSG_TIMEOUT = 0x4002;
+ /** IKE Certification validation failure */
+ public static final int IWLAN_IKEV2_CERT_INVALID = 0x4003;
+ /** Unable to resolve FQDN for the ePDG to an IP address */
+ public static final int IWLAN_DNS_RESOLUTION_NAME_FAILURE = 0x4004;
+ /** No response received from the DNS Server due to a timeout*/
+ public static final int IWLAN_DNS_RESOLUTION_TIMEOUT = 0x4005;
+
// OEM sepecific error codes. To be used by OEMs when they don't
// want to reveal error code which would be replaced by ERROR_UNSPECIFIED
public static final int OEM_DCFAILCAUSE_1 = 0x1001;
@@ -1341,6 +1419,34 @@
sFailCauseMap.put(VSNCP_RECONNECT_NOT_ALLOWED, "VSNCP_RECONNECT_NOT_ALLOWED");
sFailCauseMap.put(IPV6_PREFIX_UNAVAILABLE, "IPV6_PREFIX_UNAVAILABLE");
sFailCauseMap.put(HANDOFF_PREFERENCE_CHANGED, "HANDOFF_PREFERENCE_CHANGED");
+ sFailCauseMap.put(IWLAN_PDN_CONNECTION_REJECTION, "IWLAN_PDN_CONNECTION_REJECTION");
+ sFailCauseMap.put(IWLAN_MAX_CONNECTION_REACHED, "IWLAN_MAX_CONNECTION_REACHED");
+ sFailCauseMap.put(IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION,
+ "IWLAN_SEMANTIC_ERROR_IN_THE_TFT_OPERATION");
+ sFailCauseMap.put(IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION,
+ "IWLAN_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION");
+ sFailCauseMap.put(IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS,
+ "IWLAN_SEMANTIC_ERRORS_IN_PACKET_FILTERS");
+ sFailCauseMap.put(IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS,
+ "IWLAN_SYNTACTICAL_ERRORS_IN_PACKET_FILTERS");
+ sFailCauseMap.put(IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED,
+ "IWLAN_NON_3GPP_ACCESS_TO_EPC_NOT_ALLOWED");
+ sFailCauseMap.put(IWLAN_USER_UNKNOWN, "IWLAN_USER_UNKNOWN");
+ sFailCauseMap.put(IWLAN_NO_APN_SUBSCRIPTION, "IWLAN_NO_APN_SUBSCRIPTION");
+ sFailCauseMap.put(IWLAN_AUTHORIZATION_REJECTED, "IWLAN_AUTHORIZATION_REJECTED");
+ sFailCauseMap.put(IWLAN_ILLEGAL_ME, "IWLAN_ILLEGAL_ME");
+ sFailCauseMap.put(IWLAN_NETWORK_FAILURE, "IWLAN_NETWORK_FAILURE");
+ sFailCauseMap.put(IWLAN_RAT_TYPE_NOT_ALLOWED, "IWLAN_RAT_TYPE_NOT_ALLOWED");
+ sFailCauseMap.put(IWLAN_IMEI_NOT_ACCEPTED, "IWLAN_IMEI_NOT_ACCEPTED");
+ sFailCauseMap.put(IWLAN_PLMN_NOT_ALLOWED, "IWLAN_PLMN_NOT_ALLOWED");
+ sFailCauseMap.put(IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED,
+ "IWLAN_UNAUTHENTICATED_EMERGENCY_NOT_SUPPORTED");
+ sFailCauseMap.put(IWLAN_IKEV2_CONFIG_FAILURE, "IWLAN_IKEV2_CONFIG_FAILURE");
+ sFailCauseMap.put(IWLAN_IKEV2_AUTH_FAILURE, "IWLAN_IKEV2_AUTH_FAILURE");
+ sFailCauseMap.put(IWLAN_IKEV2_MSG_TIMEOUT, "IWLAN_IKEV2_MSG_TIMEOUT");
+ sFailCauseMap.put(IWLAN_IKEV2_CERT_INVALID, "IWLAN_IKEV2_CERT_INVALID");
+ sFailCauseMap.put(IWLAN_DNS_RESOLUTION_NAME_FAILURE, "IWLAN_DNS_RESOLUTION_NAME_FAILURE");
+ sFailCauseMap.put(IWLAN_DNS_RESOLUTION_TIMEOUT, "IWLAN_DNS_RESOLUTION_TIMEOUT");
sFailCauseMap.put(OEM_DCFAILCAUSE_1, "OEM_DCFAILCAUSE_1");
sFailCauseMap.put(OEM_DCFAILCAUSE_2, "OEM_DCFAILCAUSE_2");
sFailCauseMap.put(OEM_DCFAILCAUSE_3, "OEM_DCFAILCAUSE_3");
diff --git a/test-mock/src/android/test/mock/OWNERS b/test-mock/src/android/test/mock/OWNERS
new file mode 100644
index 0000000..9551245
--- /dev/null
+++ b/test-mock/src/android/test/mock/OWNERS
@@ -0,0 +1,3 @@
+set noparent
+
+*
diff --git a/tests/Compatibility/Android.bp b/tests/Compatibility/Android.bp
index 7dc44fa..c14e705 100644
--- a/tests/Compatibility/Android.bp
+++ b/tests/Compatibility/Android.bp
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-android_test {
+android_test_helper_app {
name: "AppCompatibilityTest",
static_libs: ["androidx.test.rules"],
// Include all test java files.
diff --git a/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt b/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt
new file mode 100644
index 0000000..6770066
--- /dev/null
+++ b/tests/net/common/java/android/net/TcpKeepalivePacketDataTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.net
+
+import android.net.InetAddresses.parseNumericAddress
+import android.os.Build
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.assertFieldCountEquals
+import com.android.testutils.assertParcelSane
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.net.InetAddress
+import kotlin.test.assertEquals
+import kotlin.test.assertNotEquals
+import kotlin.test.assertTrue
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R) // TcpKeepalivePacketData added to SDK in S
+class TcpKeepalivePacketDataTest {
+ private fun makeData(
+ srcAddress: InetAddress = parseNumericAddress("192.0.2.123"),
+ srcPort: Int = 1234,
+ dstAddress: InetAddress = parseNumericAddress("192.0.2.231"),
+ dstPort: Int = 4321,
+ data: ByteArray = byteArrayOf(1, 2, 3),
+ tcpSeq: Int = 135,
+ tcpAck: Int = 246,
+ tcpWnd: Int = 1234,
+ tcpWndScale: Int = 2,
+ ipTos: Int = 0x12,
+ ipTtl: Int = 10
+ ) = TcpKeepalivePacketData(srcAddress, srcPort, dstAddress, dstPort, data, tcpSeq, tcpAck,
+ tcpWnd, tcpWndScale, ipTos, ipTtl)
+
+ @Test
+ fun testEquals() {
+ val data1 = makeData()
+ val data2 = makeData()
+ assertEquals(data1, data2)
+ assertEquals(data1.hashCode(), data2.hashCode())
+ }
+
+ @Test
+ fun testNotEquals() {
+ assertNotEquals(makeData(srcAddress = parseNumericAddress("192.0.2.124")), makeData())
+ assertNotEquals(makeData(srcPort = 1235), makeData())
+ assertNotEquals(makeData(dstAddress = parseNumericAddress("192.0.2.232")), makeData())
+ assertNotEquals(makeData(dstPort = 4322), makeData())
+ // .equals does not test .packet, as it should be generated from the other fields
+ assertNotEquals(makeData(tcpSeq = 136), makeData())
+ assertNotEquals(makeData(tcpAck = 247), makeData())
+ assertNotEquals(makeData(tcpWnd = 1235), makeData())
+ assertNotEquals(makeData(tcpWndScale = 3), makeData())
+ assertNotEquals(makeData(ipTos = 0x14), makeData())
+ assertNotEquals(makeData(ipTtl = 11), makeData())
+
+ // Update above assertions if field is added
+ assertFieldCountEquals(5, KeepalivePacketData::class.java)
+ assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
+ }
+
+ @Test
+ fun testParcelUnparcel() {
+ assertParcelSane(makeData(), fieldCount = 6) { a, b ->
+ // .equals() does not verify .packet
+ a == b && a.packet contentEquals b.packet
+ }
+ }
+
+ @Test
+ fun testToString() {
+ val data = makeData()
+ val str = data.toString()
+
+ assertTrue(str.contains(data.srcAddress.hostAddress))
+ assertTrue(str.contains(data.srcPort.toString()))
+ assertTrue(str.contains(data.dstAddress.hostAddress))
+ assertTrue(str.contains(data.dstPort.toString()))
+ // .packet not included in toString()
+ assertTrue(str.contains(data.tcpSeq.toString()))
+ assertTrue(str.contains(data.tcpAck.toString()))
+ assertTrue(str.contains(data.tcpWindow.toString()))
+ assertTrue(str.contains(data.tcpWindowScale.toString()))
+ assertTrue(str.contains(data.ipTos.toString()))
+ assertTrue(str.contains(data.ipTtl.toString()))
+
+ // Update above assertions if field is added
+ assertFieldCountEquals(5, KeepalivePacketData::class.java)
+ assertFieldCountEquals(6, TcpKeepalivePacketData::class.java)
+ }
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java b/tests/net/java/android/net/KeepalivePacketDataUtilTest.java
similarity index 65%
rename from tests/net/java/android/net/TcpKeepalivePacketDataTest.java
rename to tests/net/java/android/net/KeepalivePacketDataUtilTest.java
index c5b25bd..fc739fb 100644
--- a/tests/net/java/android/net/TcpKeepalivePacketDataTest.java
+++ b/tests/net/java/android/net/KeepalivePacketDataUtilTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2019 The Android Open Source Project
+ * Copyright (C) 2020 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.
@@ -20,8 +20,11 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.net.util.KeepalivePacketDataUtil;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -31,7 +34,7 @@
import java.nio.ByteBuffer;
@RunWith(JUnit4.class)
-public final class TcpKeepalivePacketDataTest {
+public final class KeepalivePacketDataUtilTest {
private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 1};
private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 5};
@@ -39,7 +42,7 @@
public void setUp() {}
@Test
- public void testV4TcpKeepalivePacket() throws Exception {
+ public void testFromTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int seq = 0x11111111;
@@ -61,7 +64,7 @@
testInfo.tos = tos;
testInfo.ttl = ttl;
try {
- resultData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
+ resultData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
} catch (InvalidPacketException e) {
fail("InvalidPacketException: " + e);
}
@@ -72,8 +75,8 @@
assertEquals(testInfo.dstPort, resultData.getDstPort());
assertEquals(testInfo.seq, resultData.tcpSeq);
assertEquals(testInfo.ack, resultData.tcpAck);
- assertEquals(testInfo.rcvWnd, resultData.tcpWnd);
- assertEquals(testInfo.rcvWndScale, resultData.tcpWndScale);
+ assertEquals(testInfo.rcvWnd, resultData.tcpWindow);
+ assertEquals(testInfo.rcvWndScale, resultData.tcpWindowScale);
assertEquals(testInfo.tos, resultData.ipTos);
assertEquals(testInfo.ttl, resultData.ipTtl);
@@ -113,7 +116,7 @@
//TODO: add ipv6 test when ipv6 supported
@Test
- public void testParcel() throws Exception {
+ public void testToTcpKeepaliveStableParcelable() throws Exception {
final int srcPort = 1234;
final int dstPort = 4321;
final int sequence = 0x11111111;
@@ -135,8 +138,8 @@
testInfo.ttl = ttl;
TcpKeepalivePacketData testData = null;
TcpKeepalivePacketDataParcelable resultData = null;
- testData = TcpKeepalivePacketData.tcpKeepalivePacket(testInfo);
- resultData = testData.toStableParcelable();
+ testData = KeepalivePacketDataUtil.fromStableParcelable(testInfo);
+ resultData = KeepalivePacketDataUtil.toStableParcelable(testData);
assertArrayEquals(resultData.srcAddress, IPV4_KEEPALIVE_SRC_ADDR);
assertArrayEquals(resultData.dstAddress, IPV4_KEEPALIVE_DST_ADDR);
assertEquals(resultData.srcPort, srcPort);
@@ -154,4 +157,49 @@
+ " ack: 572662306, rcvWnd: 48000, rcvWndScale: 2, tos: 4, ttl: 64}";
assertEquals(expected, resultData.toString());
}
+
+ @Test
+ public void testParseTcpKeepalivePacketData() throws Exception {
+ final int srcPort = 1234;
+ final int dstPort = 4321;
+ final int sequence = 0x11111111;
+ final int ack = 0x22222222;
+ final int wnd = 4800;
+ final int wndScale = 2;
+ final int tos = 4;
+ final int ttl = 64;
+ final TcpKeepalivePacketDataParcelable testParcel = new TcpKeepalivePacketDataParcelable();
+ testParcel.srcAddress = IPV4_KEEPALIVE_SRC_ADDR;
+ testParcel.srcPort = srcPort;
+ testParcel.dstAddress = IPV4_KEEPALIVE_DST_ADDR;
+ testParcel.dstPort = dstPort;
+ testParcel.seq = sequence;
+ testParcel.ack = ack;
+ testParcel.rcvWnd = wnd;
+ testParcel.rcvWndScale = wndScale;
+ testParcel.tos = tos;
+ testParcel.ttl = ttl;
+
+ final KeepalivePacketData testData =
+ KeepalivePacketDataUtil.fromStableParcelable(testParcel);
+ final TcpKeepalivePacketDataParcelable parsedParcelable =
+ KeepalivePacketDataUtil.parseTcpKeepalivePacketData(testData);
+ final TcpKeepalivePacketData roundTripData =
+ KeepalivePacketDataUtil.fromStableParcelable(parsedParcelable);
+
+ // Generated packet is the same, but rcvWnd / wndScale will differ if scale is non-zero
+ assertTrue(testData.getPacket().length > 0);
+ assertArrayEquals(testData.getPacket(), roundTripData.getPacket());
+
+ testParcel.rcvWndScale = 0;
+ final KeepalivePacketData noScaleTestData =
+ KeepalivePacketDataUtil.fromStableParcelable(testParcel);
+ final TcpKeepalivePacketDataParcelable noScaleParsedParcelable =
+ KeepalivePacketDataUtil.parseTcpKeepalivePacketData(noScaleTestData);
+ final TcpKeepalivePacketData noScaleRoundTripData =
+ KeepalivePacketDataUtil.fromStableParcelable(noScaleParsedParcelable);
+ assertEquals(noScaleTestData, noScaleRoundTripData);
+ assertTrue(noScaleTestData.getPacket().length > 0);
+ assertArrayEquals(noScaleTestData.getPacket(), noScaleRoundTripData.getPacket());
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 9d308c5..8c403f1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -188,6 +188,7 @@
import android.net.RouteInfoParcel;
import android.net.SocketKeepalive;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.Uri;
import android.net.VpnManager;
import android.net.metrics.IpConnectivityLog;
@@ -1055,7 +1056,7 @@
public MockVpn(int userId) {
super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
- userId, mock(KeyStore.class));
+ mMockNetd, userId, mock(KeyStore.class));
mConfig = new VpnConfig();
}
@@ -1094,10 +1095,11 @@
mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
mNetworkCapabilities);
mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
- verify(mNetworkManagementService, times(1))
- .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
- verify(mNetworkManagementService, never())
- .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
+
+ verify(mMockNetd, times(1)).networkAddUidRanges(eq(mMockVpn.getNetId()),
+ eq(toUidRangeStableParcels(uids)));
+ verify(mMockNetd, never())
+ .networkRemoveUidRanges(eq(mMockVpn.getNetId()), any());
mAgentRegistered = true;
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
@@ -1169,6 +1171,11 @@
}
}
+ private UidRangeParcel[] toUidRangeStableParcels(final @NonNull Set<UidRange> ranges) {
+ return ranges.stream().map(
+ r -> new UidRangeParcel(r.start, r.stop)).toArray(UidRangeParcel[]::new);
+ }
+
private void mockVpn(int uid) {
synchronized (mService.mVpns) {
int userId = UserHandle.getUserId(uid);
@@ -4947,8 +4954,8 @@
expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
reset(mStatsService);
- // Captive portal change shouldn't update ifaces
- mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ // Temp metered change shouldn't update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED);
waitForIdle();
verify(mStatsService, never())
.forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
@@ -5464,6 +5471,7 @@
final Network wifi = mWiFiNetworkAgent.getNetwork();
final NetworkCapabilities initialCaps = new NetworkCapabilities();
+ initialCaps.addTransportType(TRANSPORT_VPN);
initialCaps.addCapability(NET_CAPABILITY_INTERNET);
initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
@@ -5495,44 +5503,45 @@
withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
+ final NetworkCapabilities initialCapsNotMetered = new NetworkCapabilities(initialCaps);
+ initialCapsNotMetered.addCapability(NET_CAPABILITY_NOT_METERED);
+
NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
- final boolean notDeclaredMetered = false;
- mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{}, initialCapsNotMetered, caps);
assertEquals(withNoUnderlying, caps);
caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{null}, initialCapsNotMetered, caps);
assertEquals(withNoUnderlying, caps);
caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile}, initialCapsNotMetered, caps);
assertEquals(withMobileUnderlying, caps);
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCapsNotMetered, caps);
assertEquals(withWifiUnderlying, caps);
- final boolean isDeclaredMetered = true;
withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, initialCaps, caps);
assertEquals(withWifiUnderlying, caps);
caps = new NetworkCapabilities(initialCaps);
- mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, initialCaps, caps);
assertEquals(withWifiAndMobileUnderlying, caps);
withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
caps = new NetworkCapabilities(initialCaps);
mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- caps, notDeclaredMetered);
+ initialCapsNotMetered, caps);
assertEquals(withWifiAndMobileUnderlying, caps);
caps = new NetworkCapabilities(initialCaps);
mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
- caps, notDeclaredMetered);
+ initialCapsNotMetered, caps);
assertEquals(withWifiAndMobileUnderlying, caps);
- mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+ mService.applyUnderlyingCapabilities(null, initialCapsNotMetered, caps);
assertEquals(withWifiUnderlying, caps);
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index 337507a..6e380be 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -58,6 +58,7 @@
import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.Ikev2VpnProfile;
import android.net.InetAddresses;
import android.net.IpPrefix;
@@ -70,6 +71,7 @@
import android.net.NetworkInfo.DetailedState;
import android.net.RouteInfo;
import android.net.UidRange;
+import android.net.UidRangeParcel;
import android.net.VpnManager;
import android.net.VpnService;
import android.net.ipsec.ike.IkeSessionCallback;
@@ -172,11 +174,13 @@
mPackages.put(PKGS[i], PKG_UIDS[i]);
}
}
+ private static final UidRange PRI_USER_RANGE = UidRange.createForUser(primaryUser.id);
@Mock(answer = Answers.RETURNS_DEEP_STUBS) private Context mContext;
@Mock private UserManager mUserManager;
@Mock private PackageManager mPackageManager;
@Mock private INetworkManagementService mNetService;
+ @Mock private INetd mNetd;
@Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices;
@@ -256,8 +260,7 @@
null, null);
assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id),
- UidRange.createForUser(restrictedProfileA.id)
+ PRI_USER_RANGE, UidRange.createForUser(restrictedProfileA.id)
})), ranges);
}
@@ -269,9 +272,7 @@
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id)
- })), ranges);
+ assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
}
@Test
@@ -282,15 +283,13 @@
final Set<UidRange> ranges = new ArraySet<>();
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
- assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] {
- UidRange.createForUser(primaryUser.id)
- })), ranges);
+ assertEquals(new ArraySet<>(Arrays.asList(new UidRange[] { PRI_USER_RANGE })), ranges);
}
@Test
public void testUidAllowAndDenylist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
+ final UidRange user = PRI_USER_RANGE;
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
// Allowed list
@@ -339,62 +338,67 @@
@Test
public void testLockdownChangingPackage() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
+ final UidRange user = PRI_USER_RANGE;
// Default state.
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+ user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on without lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false, null, mKeyStore));
- assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+ assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+ user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
// Set always-on with lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
}));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
+
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2],
+ user.start + PKG_UIDS[3]);
assertUnblocked(vpn, user.start + PKG_UIDS[1]);
// Switch to another app.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
}));
- assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
+ assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1],
+ user.start + PKG_UIDS[2]);
assertUnblocked(vpn, user.start + PKG_UIDS[3]);
}
@Test
public void testLockdownAllowlist() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
- final UidRange user = UidRange.createForUser(primaryUser.id);
+ final UidRange user = PRI_USER_RANGE;
// Set always-on with lockdown and allow app PKGS[2] from lockdown.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[2]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
}));
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
-
// Change allowed app list to PKGS[3].
assertTrue(vpn.setAlwaysOnPackage(
PKGS[1], true, Collections.singletonList(PKGS[3]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
}));
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2]);
assertUnblocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[3]);
@@ -402,25 +406,25 @@
// Change the VPN app.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[3]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.start + PKG_UIDS[3] - 1)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[0] - 1),
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[0] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1)
}));
assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[3]);
// Remove the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(PKGS[0], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.stop),
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop),
}));
assertBlocked(vpn, user.start + PKG_UIDS[1], user.start + PKG_UIDS[2],
user.start + PKG_UIDS[3]);
@@ -429,12 +433,12 @@
// Add the list of allowed packages.
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Collections.singletonList(PKGS[1]), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.stop)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
}));
assertBlocked(vpn, user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1]);
@@ -447,13 +451,13 @@
// allowed package should change from PGKS[1] to PKGS[2].
assertTrue(vpn.setAlwaysOnPackage(
PKGS[0], true, Arrays.asList("com.foo.app", PKGS[2], "com.bar.app"), mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[]{
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
- new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[]{
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[1] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[1] + 1, user.stop)
}));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[]{
- new UidRange(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
- new UidRange(user.start + PKG_UIDS[2] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[]{
+ new UidRangeParcel(user.start + PKG_UIDS[0] + 1, user.start + PKG_UIDS[2] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[2] + 1, user.stop)
}));
}
@@ -467,86 +471,86 @@
restrictedProfileA.flags);
tempProfile.restrictedProfileParentId = primaryUser.id;
- final UidRange user = UidRange.createForUser(primaryUser.id);
+ final UidRange user = PRI_USER_RANGE;
final UidRange profile = UidRange.createForUser(tempProfile.id);
// Set lockdown.
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true, null, mKeyStore));
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
- new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(user.start, user.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(user.start + PKG_UIDS[3] + 1, user.stop)
}));
-
// Verify restricted user isn't affected at first.
assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
// Add the restricted user.
setMockedUsers(primaryUser, tempProfile);
vpn.onUserAdded(tempProfile.id);
- verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(new UidRange[] {
- new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
- new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
}));
// Remove the restricted user.
tempProfile.partial = true;
vpn.onUserRemoved(tempProfile.id);
- verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(new UidRange[] {
- new UidRange(profile.start, profile.start + PKG_UIDS[3] - 1),
- new UidRange(profile.start + PKG_UIDS[3] + 1, profile.stop)
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(new UidRangeParcel[] {
+ new UidRangeParcel(profile.start, profile.start + PKG_UIDS[3] - 1),
+ new UidRangeParcel(profile.start + PKG_UIDS[3] + 1, profile.stop)
}));
}
@Test
public void testLockdownRuleRepeatability() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
-
+ final UidRangeParcel[] primaryUserRangeParcel = new UidRangeParcel[] {
+ new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)};
// Given legacy lockdown is already enabled,
vpn.setLockdown(true);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(
- eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+ verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(primaryUserRangeParcel));
// Enabling legacy lockdown twice should do nothing.
vpn.setLockdown(true);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+ verify(mNetd, times(1))
+ .networkRejectNonSecureVpn(anyBoolean(), any(UidRangeParcel[].class));
// And disabling should remove the rules exactly once.
vpn.setLockdown(false);
- verify(mNetService, times(1)).setAllowOnlyVpnForUids(
- eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+ verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(primaryUserRangeParcel));
// Removing the lockdown again should have no effect.
vpn.setLockdown(false);
- verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+ verify(mNetd, times(2)).networkRejectNonSecureVpn(
+ anyBoolean(), any(UidRangeParcel[].class));
}
@Test
public void testLockdownRuleReversibility() throws Exception {
final Vpn vpn = createVpn(primaryUser.id);
-
- final UidRange[] entireUser = {
- UidRange.createForUser(primaryUser.id)
+ final UidRangeParcel[] entireUser = {
+ new UidRangeParcel(PRI_USER_RANGE.start, PRI_USER_RANGE.stop)
};
- final UidRange[] exceptPkg0 = {
- new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
- new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
+ final UidRangeParcel[] exceptPkg0 = {
+ new UidRangeParcel(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+ new UidRangeParcel(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
};
- final InOrder order = inOrder(mNetService);
+ final InOrder order = inOrder(mNetd);
// Given lockdown is enabled with no package (legacy VPN),
vpn.setLockdown(true);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+ order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser));
// When a new VPN package is set the rules should change to cover that package.
vpn.prepare(null, PKGS[0], VpnManager.TYPE_VPN_SERVICE);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
+ order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(entireUser));
+ order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(exceptPkg0));
// When that VPN package is unset, everything should be undone again in reverse.
vpn.prepare(null, VpnConfig.LEGACY_VPN, VpnManager.TYPE_VPN_SERVICE);
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
- order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+ order.verify(mNetd).networkRejectNonSecureVpn(eq(false), aryEq(exceptPkg0));
+ order.verify(mNetd).networkRejectNonSecureVpn(eq(true), aryEq(entireUser));
}
@Test
@@ -1186,7 +1190,7 @@
.thenReturn(asUserContext);
final TestLooper testLooper = new TestLooper();
final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
- userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+ mNetd, userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
provider -> provider.getName().contains("VpnNetworkProvider")
));
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index ab6dced..dd3ebdb 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -519,7 +519,7 @@
String8(parser.getElementName(&len)).string(), attr);
return ATTR_NOT_FOUND;
}
- if ((str=pool->stringAt(value.data, &len)) == NULL) {
+ if ((str = UnpackOptionalString(pool->stringAt(value.data), &len)) == NULL) {
fprintf(stderr, "%s:%d: Tag <%s> attribute %s has corrupt string value.\n",
path.string(), parser.getLineNumber(),
String8(parser.getElementName(&len)).string(), attr);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index d02f44e..257e96b 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3066,7 +3066,7 @@
for (size_t ti=0; ti<N; ti++) {
// Retrieve them in the same order as the type string block.
size_t len;
- String16 typeName(p->getTypeStrings().stringAt(ti, &len));
+ String16 typeName(UnpackOptionalString(p->getTypeStrings().stringAt(ti), &len));
sp<Type> t = p->getTypes().valueFor(typeName);
LOG_ALWAYS_FATAL_IF(t == NULL && typeName != String16("<empty>"),
"Type name %s not found",
@@ -4169,7 +4169,7 @@
const size_t N = strings->size();
for (size_t i=0; i<N; i++) {
size_t len;
- mappings->add(String16(strings->stringAt(i, &len)), i);
+ mappings->add(String16(UnpackOptionalString(strings->stringAt(i), &len)), i);
}
}
return err;
diff --git a/tools/aapt/StringPool.cpp b/tools/aapt/StringPool.cpp
index 37b61bf..6cacd32 100644
--- a/tools/aapt/StringPool.cpp
+++ b/tools/aapt/StringPool.cpp
@@ -52,9 +52,9 @@
for (size_t i=0; i<N; i++) {
size_t len;
if (pool->isUTF8()) {
- uniqueStrings.add(pool->string8At(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
} else {
- uniqueStrings.add(pool->stringAt(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
}
}
@@ -66,8 +66,8 @@
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
- String8 str = pool->string8ObjectAt(s);
- printf("String #" ZD ": %s\n", (ZD_TYPE) s, str.string());
+ auto str = pool->string8ObjectAt(s);
+ printf("String #" ZD ": %s\n", (ZD_TYPE) s, (str.has_value() ? str->string() : ""));
}
}
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 439f231..82da249 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -436,9 +436,9 @@
for (size_t i=0; i<N; i++) {
size_t len;
if (pool->isUTF8()) {
- uniqueStrings.add(pool->string8At(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->string8At(i), &len));
} else {
- uniqueStrings.add(pool->stringAt(i, &len));
+ uniqueStrings.add(UnpackOptionalString(pool->stringAt(i), &len));
}
}
@@ -450,8 +450,8 @@
const size_t NS = pool->size();
for (size_t s=0; s<NS; s++) {
- String8 str = pool->string8ObjectAt(s);
- printer->Print(StringPrintf("String #%zd : %s\n", s, str.string()));
+ auto str = pool->string8ObjectAt(s);
+ printer->Print(StringPrintf("String #%zd : %s\n", s, str.has_value() ? str->string() : ""));
}
}
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 469128b..f26e995 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -751,10 +751,12 @@
switch (res_value.dataType) {
case android::Res_value::TYPE_STRING: {
const std::string str = util::GetString(src_pool, data);
- const android::ResStringPool_span* spans = src_pool.styleAt(data);
+ auto spans_result = src_pool.styleAt(data);
// Check if the string has a valid style associated with it.
- if (spans != nullptr && spans->name.index != android::ResStringPool_span::END) {
+ if (spans_result.has_value() &&
+ (*spans_result)->name.index != android::ResStringPool_span::END) {
+ const android::ResStringPool_span* spans = spans_result->unsafe_ptr();
StyleString style_str = {str};
while (spans->name.index != android::ResStringPool_span::END) {
style_str.spans.push_back(Span{util::GetString(src_pool, spans->name.index),
diff --git a/tools/aapt2/StringPool_test.cpp b/tools/aapt2/StringPool_test.cpp
index 9a7238b..6e5200b 100644
--- a/tools/aapt2/StringPool_test.cpp
+++ b/tools/aapt2/StringPool_test.cpp
@@ -223,11 +223,11 @@
std::unique_ptr<uint8_t[]> data = util::Copy(buffer);
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- size_t len = 0;
- const char16_t* str = test.stringAt(0, &len);
- EXPECT_THAT(len, Eq(1u));
- EXPECT_THAT(str, Pointee(Eq(u'\u093f')));
- EXPECT_THAT(str[1], Eq(0u));
+ auto str = test.stringAt(0);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->size(), Eq(1u));
+ EXPECT_THAT(str->data(), Pointee(Eq(u'\u093f')));
+ EXPECT_THAT(str->data()[1], Eq(0u));
}
constexpr const char* sLongString =
@@ -278,14 +278,15 @@
EXPECT_THAT(util::GetString(test, 3), Eq(sLongString));
EXPECT_THAT(util::GetString16(test, 3), Eq(util::Utf8ToUtf16(sLongString)));
- size_t len;
- EXPECT_TRUE(test.stringAt(4, &len) != nullptr || test.string8At(4, &len) != nullptr);
+ EXPECT_TRUE(test.stringAt(4).has_value() || test.string8At(4).has_value());
EXPECT_THAT(util::GetString(test, 0), Eq("style"));
EXPECT_THAT(util::GetString16(test, 0), Eq(u"style"));
- const ResStringPool_span* span = test.styleAt(0);
- ASSERT_THAT(span, NotNull());
+ auto span_result = test.styleAt(0);
+ ASSERT_TRUE(span_result.has_value());
+
+ const ResStringPool_span* span = span_result->unsafe_ptr();
EXPECT_THAT(util::GetString(test, span->name.index), Eq("b"));
EXPECT_THAT(util::GetString16(test, span->name.index), Eq(u"b"));
EXPECT_THAT(span->firstChar, Eq(0u));
@@ -318,16 +319,17 @@
// Check that the codepoints are encoded using two three-byte surrogate pairs
ResStringPool test;
ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
- size_t len;
- const char* str = test.string8At(0, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80"));
- str = test.string8At(1, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
- str = test.string8At(2, &len);
- ASSERT_THAT(str, NotNull());
- EXPECT_THAT(std::string(str, len), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+ auto str = test.string8At(0);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80"));
+
+ str = test.string8At(1);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+
+ str = test.string8At(2);
+ ASSERT_TRUE(str.has_value());
+ EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
// Check that retrieving the strings returns the original UTF-8 character bytes
EXPECT_THAT(util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
diff --git a/tools/aapt2/cmd/Compile_test.cpp b/tools/aapt2/cmd/Compile_test.cpp
index fb786a3..ae9f792 100644
--- a/tools/aapt2/cmd/Compile_test.cpp
+++ b/tools/aapt2/cmd/Compile_test.cpp
@@ -252,5 +252,4 @@
AssertTranslations(this, "donottranslate", expected_not_translatable);
AssertTranslations(this, "donottranslate_foo", expected_not_translatable);
}
-
} // namespace aapt
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index fd12d02..faabe46 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -730,22 +730,6 @@
return true;
}
-static android::ApkAssetsCookie FindFrameworkAssetManagerCookie(
- const android::AssetManager2& assets) {
- using namespace android;
-
- // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
- // we're looking for the first attribute resource in the system package.
- Res_value val{};
- ResTable_config config{};
- uint32_t type_spec_flags;
- ApkAssetsCookie idx = assets.GetResource(0x01010000, true /** may_be_bag */,
- 0 /** density_override */, &val, &config,
- &type_spec_flags);
-
- return idx;
-}
-
class Linker {
public:
Linker(LinkContext* context, const LinkOptions& options)
@@ -758,8 +742,12 @@
void ExtractCompileSdkVersions(android::AssetManager2* assets) {
using namespace android;
- android::ApkAssetsCookie cookie = FindFrameworkAssetManagerCookie(*assets);
- if (cookie == android::kInvalidCookie) {
+ // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
+ // we're looking for the first attribute resource in the system package.
+ android::ApkAssetsCookie cookie;
+ if (auto value = assets->GetResource(0x01010000, true /** may_be_bag */); value.has_value()) {
+ cookie = value->cookie;
+ } else {
// No Framework assets loaded. Not a failure.
return;
}
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 6932baf..f8b8a1c 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -189,16 +189,16 @@
ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/bar", ResourceId(0x7f050000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenEntriesWithGapsInIds) {
@@ -603,16 +603,16 @@
2u, ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/0_resource_name_obfuscated",
- ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f040000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
- ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, ObfuscatingResourceNamesWithNameCollapseExemptionsSucceeds) {
@@ -659,16 +659,16 @@
2u, ResTable_config::CONFIG_VERSION));
std::u16string foo_str = u"foo";
- ssize_t idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
- ASSERT_GE(idx, 0);
+ auto idx = res_table.getTableStringBlock(0)->indexOfString(foo_str.data(), foo_str.size());
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:string/test", ResourceId(0x7f040000), {},
- Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
std::u16string bar_path = u"res/layout/bar.xml";
idx = res_table.getTableStringBlock(0)->indexOfString(bar_path.data(), bar_path.size());
- ASSERT_GE(idx, 0);
+ ASSERT_TRUE(idx.has_value());
EXPECT_TRUE(Exists(&res_table, "com.app.test:layout/0_resource_name_obfuscated",
- ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)idx, 0u));
+ ResourceId(0x7f050000), {}, Res_value::TYPE_STRING, (uint32_t)*idx, 0u));
}
TEST_F(TableFlattenerTest, FlattenOverlayable) {
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 897fa80..ad716c7 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -265,21 +265,22 @@
static std::unique_ptr<SymbolTable::Symbol> LookupAttributeInTable(
android::AssetManager2& am, ResourceId id) {
+ using namespace android;
if (am.GetApkAssets().empty()) {
return {};
}
- const android::ResolvedBag* bag = am.GetBag(id.id);
- if (bag == nullptr) {
+ auto bag_result = am.GetBag(id.id);
+ if (!bag_result.has_value()) {
return nullptr;
}
// We found a resource.
std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>(id);
-
+ const ResolvedBag* bag = *bag_result;
const size_t count = bag->entry_count;
for (uint32_t i = 0; i < count; i++) {
- if (bag->entries[i].key == android::ResTable_map::ATTR_TYPE) {
+ if (bag->entries[i].key == ResTable_map::ATTR_TYPE) {
s->attribute = std::make_shared<Attribute>(bag->entries[i].value.data);
break;
}
@@ -287,25 +288,25 @@
if (s->attribute) {
for (size_t i = 0; i < count; i++) {
- const android::ResolvedBag::Entry& map_entry = bag->entries[i];
+ const ResolvedBag::Entry& map_entry = bag->entries[i];
if (Res_INTERNALID(map_entry.key)) {
switch (map_entry.key) {
- case android::ResTable_map::ATTR_MIN:
+ case ResTable_map::ATTR_MIN:
s->attribute->min_int = static_cast<int32_t>(map_entry.value.data);
break;
- case android::ResTable_map::ATTR_MAX:
+ case ResTable_map::ATTR_MAX:
s->attribute->max_int = static_cast<int32_t>(map_entry.value.data);
break;
}
continue;
}
- android::AssetManager2::ResourceName name;
- if (!am.GetResourceName(map_entry.key, &name)) {
+ auto name = am.GetResourceName(map_entry.key);
+ if (!name.has_value()) {
return nullptr;
}
- Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(name);
+ Maybe<ResourceName> parsed_name = ResourceUtils::ToResourceName(*name);
if (!parsed_name) {
return nullptr;
}
@@ -328,7 +329,7 @@
bool found = false;
ResourceId res_id = 0;
- uint32_t type_spec_flags;
+ uint32_t type_spec_flags = 0;
ResourceName real_name;
// There can be mangled resources embedded within other packages. Here we will
@@ -340,8 +341,19 @@
real_name.package = package_name;
}
- res_id = asset_manager_.GetResourceId(real_name.to_string());
- if (res_id.is_valid_static() && asset_manager_.GetResourceFlags(res_id.id, &type_spec_flags)) {
+ auto real_res_id = asset_manager_.GetResourceId(real_name.to_string());
+ if (!real_res_id.has_value()) {
+ return true;
+ }
+
+ res_id.id = *real_res_id;
+ if (!res_id.is_valid_static()) {
+ return true;
+ }
+
+ auto value = asset_manager_.GetResource(res_id.id, true /* may_be_bag */);
+ if (value.has_value()) {
+ type_spec_flags = value->flags;
found = true;
return false;
}
@@ -371,11 +383,11 @@
static Maybe<ResourceName> GetResourceName(android::AssetManager2& am,
ResourceId id) {
- android::AssetManager2::ResourceName name;
- if (!am.GetResourceName(id.id, &name)) {
+ auto name = am.GetResourceName(id.id);
+ if (!name.has_value()) {
return {};
}
- return ResourceUtils::ToResourceName(name);
+ return ResourceUtils::ToResourceName(*name);
}
std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::FindById(
@@ -394,9 +406,8 @@
return {};
}
-
- uint32_t type_spec_flags = 0;
- if (!asset_manager_.GetResourceFlags(id.id, &type_spec_flags)) {
+ auto value = asset_manager_.GetResource(id.id, true /* may_be_bag */);
+ if (!value.has_value()) {
return {};
}
@@ -411,7 +422,7 @@
}
if (s) {
- s->is_public = (type_spec_flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+ s->is_public = (value->flags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
return s;
}
return {};
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 37ce65e..ef33c34 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -531,19 +531,15 @@
}
StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char16_t* str = pool.stringAt(idx, &len);
- if (str != nullptr) {
- return StringPiece16(str, len);
+ if (auto str = pool.stringAt(idx)) {
+ return *str;
}
return StringPiece16();
}
std::string GetString(const android::ResStringPool& pool, size_t idx) {
- size_t len;
- const char* str = pool.string8At(idx, &len);
- if (str != nullptr) {
- return ModifiedUtf8ToUtf8(std::string(str, len));
+ if (auto str = pool.string8At(idx)) {
+ return ModifiedUtf8ToUtf8(str->to_string());
}
return Utf16ToUtf8(GetString16(pool, idx));
}
diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp
index d3eb012..e6966db 100644
--- a/tools/split-select/Main.cpp
+++ b/tools/split-select/Main.cpp
@@ -182,14 +182,18 @@
if (type >= Res_value::TYPE_FIRST_INT && type <= Res_value::TYPE_LAST_INT) {
outInfo.minSdkVersion = xml.getAttributeData(idx);
} else if (type == Res_value::TYPE_STRING) {
- String8 minSdk8(xml.getStrings().string8ObjectAt(idx));
- char* endPtr;
- int minSdk = strtol(minSdk8.string(), &endPtr, 10);
- if (endPtr != minSdk8.string() + minSdk8.size()) {
- fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
- minSdk8.string());
+ auto minSdk8 = xml.getStrings().string8ObjectAt(idx);
+ if (!minSdk8.has_value()) {
+ fprintf(stderr, "warning: failed to retrieve android:minSdkVersion.\n");
} else {
- outInfo.minSdkVersion = minSdk;
+ char *endPtr;
+ int minSdk = strtol(minSdk8->string(), &endPtr, 10);
+ if (endPtr != minSdk8->string() + minSdk8->size()) {
+ fprintf(stderr, "warning: failed to parse android:minSdkVersion '%s'\n",
+ minSdk8->string());
+ } else {
+ outInfo.minSdkVersion = minSdk;
+ }
}
} else {
fprintf(stderr, "warning: unrecognized value for android:minSdkVersion.\n");
diff --git a/tools/split-select/OWNERS b/tools/split-select/OWNERS
new file mode 100644
index 0000000..6c50ede
--- /dev/null
+++ b/tools/split-select/OWNERS
@@ -0,0 +1 @@
+include /core/java/android/content/res/OWNERS
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/.clang-format b/tools/stats_log_api_gen/.clang-format
deleted file mode 100644
index cead3a0..0000000
--- a/tools/stats_log_api_gen/.clang-format
+++ /dev/null
@@ -1,17 +0,0 @@
-BasedOnStyle: Google
-AllowShortIfStatementsOnASingleLine: true
-AllowShortFunctionsOnASingleLine: false
-AllowShortLoopsOnASingleLine: true
-BinPackArguments: true
-BinPackParameters: true
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ContinuationIndentWidth: 8
-DerivePointerAlignment: false
-IndentWidth: 4
-PointerAlignment: Left
-TabWidth: 4
-AccessModifierOffset: -4
-IncludeCategories:
- - Regex: '^"Log\.h"'
- Priority: -1
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
deleted file mode 100644
index c0893f7..0000000
--- a/tools/stats_log_api_gen/Android.bp
+++ /dev/null
@@ -1,134 +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.
-//
-
-// ==========================================================
-// Build the host executable: stats-log-api-gen
-// ==========================================================
-cc_binary_host {
- name: "stats-log-api-gen",
- srcs: [
- "Collation.cpp",
- "java_writer.cpp",
- "java_writer_q.cpp",
- "main.cpp",
- "native_writer.cpp",
- "utils.cpp",
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
-
- shared_libs: [
- "libstats_proto_host",
- "libprotobuf-cpp-full",
- "libbase",
- ],
-
- proto: {
- type: "full",
- },
-}
-
-// ==========================================================
-// Build the host test executable: stats-log-api-gen
-// ==========================================================
-cc_test_host {
- name: "stats-log-api-gen-test",
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- "-g",
- "-DUNIT_TEST",
- ],
- srcs: [
- "Collation.cpp",
- "test_collation.cpp",
- "test.proto",
- ],
-
- static_libs: [
- "libgmock_host",
- ],
-
- shared_libs: [
- "libstats_proto_host",
- "libprotobuf-cpp-full",
- ],
-
- proto: {
- type: "full",
- include_dirs: [
- "external/protobuf/src",
- ],
- },
-}
-
-// ==========================================================
-// Native library
-// ==========================================================
-genrule {
- name: "statslog.h",
- tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --header $(genDir)/statslog.h",
- out: [
- "statslog.h",
- ],
-}
-
-genrule {
- name: "statslog.cpp",
- tools: ["stats-log-api-gen"],
- cmd: "$(location stats-log-api-gen) --cpp $(genDir)/statslog.cpp",
- out: [
- "statslog.cpp",
- ],
-}
-
-cc_library {
- name: "libstatslog",
- host_supported: true,
- generated_sources: [
- "statslog.cpp",
- ],
- generated_headers: [
- "statslog.h"
- ],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- export_generated_headers: [
- "statslog.h"
- ],
- shared_libs: [
- "liblog",
- "libcutils",
- ],
- target: {
- android: {
- shared_libs: ["libstatssocket"],
- },
- host: {
- static_libs: ["libstatssocket"],
- },
- darwin: {
- enabled: false,
- },
- },
-}
-
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
deleted file mode 100644
index 2608097..0000000
--- a/tools/stats_log_api_gen/Collation.cpp
+++ /dev/null
@@ -1,576 +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.
- */
-
-#include "Collation.h"
-
-#include <stdio.h>
-
-#include <map>
-
-#include "frameworks/proto_logging/stats/atoms.pb.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using google::protobuf::EnumDescriptor;
-using google::protobuf::FieldDescriptor;
-using google::protobuf::FileDescriptor;
-using google::protobuf::SourceLocation;
-using std::make_shared;
-using std::map;
-
-const bool dbg = false;
-
-//
-// AtomDecl class
-//
-
-AtomDecl::AtomDecl() : code(0), name() {
-}
-
-AtomDecl::AtomDecl(const AtomDecl& that)
- : code(that.code),
- name(that.name),
- message(that.message),
- fields(that.fields),
- fieldNumberToAnnotations(that.fieldNumberToAnnotations),
- primaryFields(that.primaryFields),
- exclusiveField(that.exclusiveField),
- defaultState(that.defaultState),
- triggerStateReset(that.triggerStateReset),
- nested(that.nested),
- uidField(that.uidField) {
-}
-
-AtomDecl::AtomDecl(int c, const string& n, const string& m) : code(c), name(n), message(m) {
-}
-
-AtomDecl::~AtomDecl() {
-}
-
-/**
- * Print an error message for a FieldDescriptor, including the file name and
- * line number.
- */
-static void print_error(const FieldDescriptor* field, const char* format, ...) {
- const Descriptor* message = field->containing_type();
- const FileDescriptor* file = message->file();
-
- SourceLocation loc;
- if (field->GetSourceLocation(&loc)) {
- // TODO: this will work if we can figure out how to pass
- // --include_source_info to protoc
- fprintf(stderr, "%s:%d: ", file->name().c_str(), loc.start_line);
- } else {
- fprintf(stderr, "%s: ", file->name().c_str());
- }
- va_list args;
- va_start(args, format);
- vfprintf(stderr, format, args);
- va_end(args);
-}
-
-/**
- * Convert a protobuf type into a java type.
- */
-static java_type_t java_type(const FieldDescriptor* field) {
- int protoType = field->type();
- switch (protoType) {
- case FieldDescriptor::TYPE_DOUBLE:
- return JAVA_TYPE_DOUBLE;
- case FieldDescriptor::TYPE_FLOAT:
- return JAVA_TYPE_FLOAT;
- case FieldDescriptor::TYPE_INT64:
- return JAVA_TYPE_LONG;
- case FieldDescriptor::TYPE_UINT64:
- return JAVA_TYPE_LONG;
- case FieldDescriptor::TYPE_INT32:
- return JAVA_TYPE_INT;
- case FieldDescriptor::TYPE_FIXED64:
- return JAVA_TYPE_LONG;
- case FieldDescriptor::TYPE_FIXED32:
- return JAVA_TYPE_INT;
- case FieldDescriptor::TYPE_BOOL:
- return JAVA_TYPE_BOOLEAN;
- case FieldDescriptor::TYPE_STRING:
- return JAVA_TYPE_STRING;
- case FieldDescriptor::TYPE_GROUP:
- return JAVA_TYPE_UNKNOWN;
- case FieldDescriptor::TYPE_MESSAGE:
- // TODO: not the final package name
- if (field->message_type()->full_name() == "android.os.statsd.AttributionNode") {
- return JAVA_TYPE_ATTRIBUTION_CHAIN;
- } else if (field->message_type()->full_name() == "android.os.statsd.KeyValuePair") {
- return JAVA_TYPE_KEY_VALUE_PAIR;
- } else if (field->options().GetExtension(os::statsd::log_mode) ==
- os::statsd::LogMode::MODE_BYTES) {
- return JAVA_TYPE_BYTE_ARRAY;
- } else {
- return JAVA_TYPE_OBJECT;
- }
- case FieldDescriptor::TYPE_BYTES:
- return JAVA_TYPE_BYTE_ARRAY;
- case FieldDescriptor::TYPE_UINT32:
- return JAVA_TYPE_INT;
- case FieldDescriptor::TYPE_ENUM:
- return JAVA_TYPE_ENUM;
- case FieldDescriptor::TYPE_SFIXED32:
- return JAVA_TYPE_INT;
- case FieldDescriptor::TYPE_SFIXED64:
- return JAVA_TYPE_LONG;
- case FieldDescriptor::TYPE_SINT32:
- return JAVA_TYPE_INT;
- case FieldDescriptor::TYPE_SINT64:
- return JAVA_TYPE_LONG;
- default:
- return JAVA_TYPE_UNKNOWN;
- }
-}
-
-/**
- * Gather the enums info.
- */
-void collate_enums(const EnumDescriptor& enumDescriptor, AtomField* atomField) {
- for (int i = 0; i < enumDescriptor.value_count(); i++) {
- atomField->enumValues[enumDescriptor.value(i)->number()] =
- enumDescriptor.value(i)->name().c_str();
- }
-}
-
-static void addAnnotationToAtomDecl(AtomDecl* atomDecl, const int fieldNumber,
- const AnnotationId annotationId,
- const AnnotationType annotationType,
- const AnnotationValue annotationValue) {
- if (dbg) {
- printf(" Adding annotation to %s: [%d] = {id: %d, type: %d}\n", atomDecl->name.c_str(),
- fieldNumber, annotationId, annotationType);
- }
- atomDecl->fieldNumberToAnnotations[fieldNumber].insert(
- make_shared<Annotation>(annotationId, atomDecl->code, annotationType, annotationValue));
-}
-
-static int collate_field_annotations(AtomDecl* atomDecl, const FieldDescriptor* field,
- const int fieldNumber, const java_type_t& javaType) {
- int errorCount = 0;
-
- if (field->options().HasExtension(os::statsd::state_field_option)) {
- const os::statsd::StateAtomFieldOption& stateFieldOption =
- field->options().GetExtension(os::statsd::state_field_option);
- const bool primaryField = stateFieldOption.primary_field();
- const bool exclusiveState = stateFieldOption.exclusive_state();
- const bool primaryFieldFirstUid = stateFieldOption.primary_field_first_uid();
-
- // Check the field is only one of primaryField, exclusiveState, or primaryFieldFirstUid.
- if (primaryField + primaryFieldFirstUid + exclusiveState > 1) {
- print_error(field,
- "Field can be max 1 of primary_field, exclusive_state, "
- "or primary_field_first_uid: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- }
-
- if (primaryField) {
- if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
- javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
- print_error(field, "Invalid primary state field: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- } else {
- atomDecl->primaryFields.push_back(fieldNumber);
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_PRIMARY_FIELD,
- ANNOTATION_TYPE_BOOL, AnnotationValue(true));
- }
- }
-
- if (primaryFieldFirstUid) {
- if (javaType != JAVA_TYPE_ATTRIBUTION_CHAIN) {
- print_error(field,
- "PRIMARY_FIELD_FIRST_UID annotation is only for AttributionChains: "
- "'%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- } else {
- atomDecl->primaryFields.push_back(FIRST_UID_IN_CHAIN_ID);
- addAnnotationToAtomDecl(atomDecl, fieldNumber,
- ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, ANNOTATION_TYPE_BOOL,
- AnnotationValue(true));
- }
- }
-
- if (exclusiveState) {
- if (javaType == JAVA_TYPE_UNKNOWN || javaType == JAVA_TYPE_ATTRIBUTION_CHAIN ||
- javaType == JAVA_TYPE_OBJECT || javaType == JAVA_TYPE_BYTE_ARRAY) {
- print_error(field, "Invalid exclusive state field: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- }
-
- if (atomDecl->exclusiveField != 0) {
- print_error(field,
- "Cannot have more than one exclusive state field in an "
- "atom: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- } else {
- atomDecl->exclusiveField = fieldNumber;
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_EXCLUSIVE_STATE,
- ANNOTATION_TYPE_BOOL, AnnotationValue(true));
- }
-
- if (stateFieldOption.has_default_state_value()) {
- const int defaultState = stateFieldOption.default_state_value();
- atomDecl->defaultState = defaultState;
-
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_DEFAULT_STATE,
- ANNOTATION_TYPE_INT, AnnotationValue(defaultState));
- }
-
- if (stateFieldOption.has_trigger_state_reset_value()) {
- const int triggerStateReset = stateFieldOption.trigger_state_reset_value();
-
- atomDecl->triggerStateReset = triggerStateReset;
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_TRIGGER_STATE_RESET,
- ANNOTATION_TYPE_INT, AnnotationValue(triggerStateReset));
- }
-
- if (stateFieldOption.has_nested()) {
- const bool nested = stateFieldOption.nested();
- atomDecl->nested = nested;
-
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_STATE_NESTED,
- ANNOTATION_TYPE_BOOL, AnnotationValue(nested));
- }
- }
- }
-
- if (field->options().GetExtension(os::statsd::is_uid) == true) {
- if (javaType != JAVA_TYPE_INT) {
- print_error(field, "is_uid annotation can only be applied to int32 fields: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- }
-
- if (atomDecl->uidField == 0) {
- atomDecl->uidField = fieldNumber;
-
- addAnnotationToAtomDecl(atomDecl, fieldNumber, ANNOTATION_ID_IS_UID,
- ANNOTATION_TYPE_BOOL, AnnotationValue(true));
- } else {
- print_error(field,
- "Cannot have more than one field in an atom with is_uid "
- "annotation: '%s'\n",
- atomDecl->message.c_str());
- errorCount++;
- }
- }
-
- return errorCount;
-}
-
-/**
- * Gather the info about an atom proto.
- */
-int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature) {
- int errorCount = 0;
-
- // Build a sorted list of the fields. Descriptor has them in source file
- // order.
- map<int, const FieldDescriptor*> fields;
- for (int j = 0; j < atom->field_count(); j++) {
- const FieldDescriptor* field = atom->field(j);
- fields[field->number()] = field;
- }
-
- // Check that the parameters start at 1 and go up sequentially.
- int expectedNumber = 1;
- for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
- it++) {
- const int number = it->first;
- const FieldDescriptor* field = it->second;
- if (number != expectedNumber) {
- print_error(field,
- "Fields must be numbered consecutively starting at 1:"
- " '%s' is %d but should be %d\n",
- field->name().c_str(), number, expectedNumber);
- errorCount++;
- expectedNumber = number;
- continue;
- }
- expectedNumber++;
- }
-
- // Check that only allowed types are present. Remove any invalid ones.
- for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
- it++) {
- const FieldDescriptor* field = it->second;
- bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
- os::statsd::LogMode::MODE_BYTES;
-
- java_type_t javaType = java_type(field);
-
- if (javaType == JAVA_TYPE_UNKNOWN) {
- print_error(field, "Unknown type for field: %s\n", field->name().c_str());
- errorCount++;
- continue;
- } else if (javaType == JAVA_TYPE_OBJECT && atomDecl->code < PULL_ATOM_START_ID) {
- // Allow attribution chain, but only at position 1.
- print_error(field, "Message type not allowed for field in pushed atoms: %s\n",
- field->name().c_str());
- errorCount++;
- continue;
- } else if (javaType == JAVA_TYPE_BYTE_ARRAY && !isBinaryField) {
- print_error(field, "Raw bytes type not allowed for field: %s\n", field->name().c_str());
- errorCount++;
- continue;
- }
-
- if (isBinaryField && javaType != JAVA_TYPE_BYTE_ARRAY) {
- print_error(field, "Cannot mark field %s as bytes.\n", field->name().c_str());
- errorCount++;
- continue;
- }
-
- // Doubles are not supported yet.
- if (javaType == JAVA_TYPE_DOUBLE) {
- print_error(field,
- "Doubles are not supported in atoms. Please change field %s "
- "to float\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
-
- if (field->is_repeated() &&
- !(javaType == JAVA_TYPE_ATTRIBUTION_CHAIN || javaType == JAVA_TYPE_KEY_VALUE_PAIR)) {
- print_error(field,
- "Repeated fields are not supported in atoms. Please make "
- "field %s not "
- "repeated.\n",
- field->name().c_str());
- errorCount++;
- continue;
- }
- }
-
- // Check that if there's an attribution chain, it's at position 1.
- for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
- it++) {
- int number = it->first;
- if (number != 1) {
- const FieldDescriptor* field = it->second;
- java_type_t javaType = java_type(field);
- if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- print_error(field,
- "AttributionChain fields must have field id 1, in message: '%s'\n",
- atom->name().c_str());
- errorCount++;
- }
- }
- }
-
- // Build the type signature and the atom data.
- for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
- it++) {
- const FieldDescriptor* field = it->second;
- java_type_t javaType = java_type(field);
- bool isBinaryField = field->options().GetExtension(os::statsd::log_mode) ==
- os::statsd::LogMode::MODE_BYTES;
-
- AtomField atField(field->name(), javaType);
-
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- collate_enums(*field->enum_type(), &atField);
- }
-
- // Generate signature for pushed atoms
- if (atomDecl->code < PULL_ATOM_START_ID) {
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature->push_back(JAVA_TYPE_INT);
- } else if (javaType == JAVA_TYPE_OBJECT && isBinaryField) {
- signature->push_back(JAVA_TYPE_BYTE_ARRAY);
- } else {
- signature->push_back(javaType);
- }
- }
-
- atomDecl->fields.push_back(atField);
-
- errorCount += collate_field_annotations(atomDecl, field, it->first, javaType);
- }
-
- return errorCount;
-}
-
-// This function flattens the fields of the AttributionNode proto in an Atom
-// proto and generates the corresponding atom decl and signature.
-bool get_non_chained_node(const Descriptor* atom, AtomDecl* atomDecl,
- vector<java_type_t>* signature) {
- // Build a sorted list of the fields. Descriptor has them in source file
- // order.
- map<int, const FieldDescriptor*> fields;
- for (int j = 0; j < atom->field_count(); j++) {
- const FieldDescriptor* field = atom->field(j);
- fields[field->number()] = field;
- }
-
- AtomDecl attributionDecl;
- vector<java_type_t> attributionSignature;
- collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
- &attributionSignature);
-
- // Build the type signature and the atom data.
- bool has_attribution_node = false;
- for (map<int, const FieldDescriptor*>::const_iterator it = fields.begin(); it != fields.end();
- it++) {
- const FieldDescriptor* field = it->second;
- java_type_t javaType = java_type(field);
- if (javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- atomDecl->fields.insert(atomDecl->fields.end(), attributionDecl.fields.begin(),
- attributionDecl.fields.end());
- signature->insert(signature->end(), attributionSignature.begin(),
- attributionSignature.end());
- has_attribution_node = true;
-
- } else {
- AtomField atField(field->name(), javaType);
- if (javaType == JAVA_TYPE_ENUM) {
- // All enums are treated as ints when it comes to function signatures.
- signature->push_back(JAVA_TYPE_INT);
- collate_enums(*field->enum_type(), &atField);
- } else {
- signature->push_back(javaType);
- }
- atomDecl->fields.push_back(atField);
- }
- }
- return has_attribution_node;
-}
-
-static void populateFieldNumberToAtomDeclSet(const shared_ptr<AtomDecl>& atomDecl,
- FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet) {
- for (FieldNumberToAnnotations::const_iterator it = atomDecl->fieldNumberToAnnotations.begin();
- it != atomDecl->fieldNumberToAnnotations.end(); it++) {
- const int fieldNumber = it->first;
- (*fieldNumberToAtomDeclSet)[fieldNumber].insert(atomDecl);
- }
-}
-
-/**
- * Gather the info about the atoms.
- */
-int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms) {
- int errorCount = 0;
-
- for (int i = 0; i < descriptor->field_count(); i++) {
- const FieldDescriptor* atomField = descriptor->field(i);
-
- if (moduleName != DEFAULT_MODULE_NAME) {
- const int moduleCount = atomField->options().ExtensionSize(os::statsd::module);
- int j;
- for (j = 0; j < moduleCount; ++j) {
- const string atomModuleName =
- atomField->options().GetExtension(os::statsd::module, j);
- if (atomModuleName == moduleName) {
- break;
- }
- }
-
- // This atom is not in the module we're interested in; skip it.
- if (moduleCount == j) {
- if (dbg) {
- printf(" Skipping %s (%d)\n", atomField->name().c_str(), atomField->number());
- }
- continue;
- }
- }
-
- if (dbg) {
- printf(" %s (%d)\n", atomField->name().c_str(), atomField->number());
- }
-
- // StatsEvent only has one oneof, which contains only messages. Don't allow
- // other types.
- if (atomField->type() != FieldDescriptor::TYPE_MESSAGE) {
- print_error(atomField,
- "Bad type for atom. StatsEvent can only have message type "
- "fields: %s\n",
- atomField->name().c_str());
- errorCount++;
- continue;
- }
-
- const Descriptor* atom = atomField->message_type();
- shared_ptr<AtomDecl> atomDecl =
- make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
-
- if (atomDecl->code < PULL_ATOM_START_ID &&
- atomField->options().GetExtension(os::statsd::truncate_timestamp)) {
- addAnnotationToAtomDecl(atomDecl.get(), ATOM_ID_FIELD_NUMBER,
- ANNOTATION_ID_TRUNCATE_TIMESTAMP, ANNOTATION_TYPE_BOOL,
- AnnotationValue(true));
- if (dbg) {
- printf("%s can have timestamp truncated\n", atomField->name().c_str());
- }
- }
-
- vector<java_type_t> signature;
- errorCount += collate_atom(atom, atomDecl.get(), &signature);
- if (atomDecl->primaryFields.size() != 0 && atomDecl->exclusiveField == 0) {
- print_error(atomField, "Cannot have a primary field without an exclusive field: %s\n",
- atomField->name().c_str());
- errorCount++;
- continue;
- }
-
- FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = atoms->signatureInfoMap[signature];
- populateFieldNumberToAtomDeclSet(atomDecl, &fieldNumberToAtomDeclSet);
-
- atoms->decls.insert(atomDecl);
-
- shared_ptr<AtomDecl> nonChainedAtomDecl =
- make_shared<AtomDecl>(atomField->number(), atomField->name(), atom->name());
- vector<java_type_t> nonChainedSignature;
- if (get_non_chained_node(atom, nonChainedAtomDecl.get(), &nonChainedSignature)) {
- FieldNumberToAtomDeclSet& nonChainedFieldNumberToAtomDeclSet =
- atoms->nonChainedSignatureInfoMap[nonChainedSignature];
- populateFieldNumberToAtomDeclSet(nonChainedAtomDecl,
- &nonChainedFieldNumberToAtomDeclSet);
-
- atoms->non_chained_decls.insert(nonChainedAtomDecl);
- }
- }
-
- if (dbg) {
- printf("signatures = [\n");
- for (SignatureInfoMap::const_iterator it = atoms->signatureInfoMap.begin();
- it != atoms->signatureInfoMap.end(); it++) {
- printf(" ");
- for (vector<java_type_t>::const_iterator jt = it->first.begin(); jt != it->first.end();
- jt++) {
- printf(" %d", (int)*jt);
- }
- printf("\n");
- }
- printf("]\n");
- }
-
- return errorCount;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
deleted file mode 100644
index 3deb3ae..0000000
--- a/tools/stats_log_api_gen/Collation.h
+++ /dev/null
@@ -1,201 +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 ANDROID_STATS_LOG_API_GEN_COLLATION_H
-#define ANDROID_STATS_LOG_API_GEN_COLLATION_H
-
-#include <google/protobuf/descriptor.h>
-#include <stdint.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "frameworks/proto_logging/stats/atom_field_options.pb.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using google::protobuf::Descriptor;
-using google::protobuf::FieldDescriptor;
-using std::map;
-using std::set;
-using std::shared_ptr;
-using std::string;
-using std::vector;
-
-const int PULL_ATOM_START_ID = 10000;
-
-const int FIRST_UID_IN_CHAIN_ID = 0;
-
-enum AnnotationId : uint8_t {
- ANNOTATION_ID_IS_UID = 1,
- ANNOTATION_ID_TRUNCATE_TIMESTAMP = 2,
- ANNOTATION_ID_PRIMARY_FIELD = 3,
- ANNOTATION_ID_EXCLUSIVE_STATE = 4,
- ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID = 5,
- ANNOTATION_ID_DEFAULT_STATE = 6,
- ANNOTATION_ID_TRIGGER_STATE_RESET = 7,
- ANNOTATION_ID_STATE_NESTED = 8,
-};
-
-const int ATOM_ID_FIELD_NUMBER = -1;
-
-const string DEFAULT_MODULE_NAME = "DEFAULT";
-
-/**
- * The types for atom parameters.
- */
-typedef enum {
- JAVA_TYPE_UNKNOWN = 0,
-
- JAVA_TYPE_ATTRIBUTION_CHAIN = 1,
- JAVA_TYPE_BOOLEAN = 2,
- JAVA_TYPE_INT = 3,
- JAVA_TYPE_LONG = 4,
- JAVA_TYPE_FLOAT = 5,
- JAVA_TYPE_DOUBLE = 6,
- JAVA_TYPE_STRING = 7,
- JAVA_TYPE_ENUM = 8,
- JAVA_TYPE_KEY_VALUE_PAIR = 9,
-
- JAVA_TYPE_OBJECT = -1,
- JAVA_TYPE_BYTE_ARRAY = -2,
-} java_type_t;
-
-enum AnnotationType {
- ANNOTATION_TYPE_UNKNOWN = 0,
- ANNOTATION_TYPE_INT = 1,
- ANNOTATION_TYPE_BOOL = 2,
-};
-
-union AnnotationValue {
- int intValue;
- bool boolValue;
-
- AnnotationValue(const int value) : intValue(value) {
- }
- AnnotationValue(const bool value) : boolValue(value) {
- }
-};
-
-struct Annotation {
- const AnnotationId annotationId;
- const int atomId;
- AnnotationType type;
- AnnotationValue value;
-
- inline Annotation(AnnotationId annotationId, int atomId, AnnotationType type,
- AnnotationValue value)
- : annotationId(annotationId), atomId(atomId), type(type), value(value) {
- }
- inline ~Annotation() {
- }
-
- inline bool operator<(const Annotation& that) const {
- return atomId == that.atomId ? annotationId < that.annotationId : atomId < that.atomId;
- }
-};
-
-struct SharedComparator {
- template <typename T>
- inline bool operator()(const shared_ptr<T>& lhs, const shared_ptr<T>& rhs) const {
- return (*lhs) < (*rhs);
- }
-};
-
-using AnnotationSet = set<shared_ptr<Annotation>, SharedComparator>;
-
-using FieldNumberToAnnotations = map<int, AnnotationSet>;
-
-/**
- * The name and type for an atom field.
- */
-struct AtomField {
- string name;
- java_type_t javaType;
-
- // If the field is of type enum, the following map contains the list of enum
- // values.
- map<int /* numeric value */, string /* value name */> enumValues;
-
- inline AtomField() : name(), javaType(JAVA_TYPE_UNKNOWN) {
- }
- inline AtomField(const AtomField& that)
- : name(that.name), javaType(that.javaType), enumValues(that.enumValues) {
- }
-
- inline AtomField(string n, java_type_t jt) : name(n), javaType(jt) {
- }
- inline ~AtomField() {
- }
-};
-
-/**
- * The name and code for an atom.
- */
-struct AtomDecl {
- int code;
- string name;
-
- string message;
- vector<AtomField> fields;
-
- FieldNumberToAnnotations fieldNumberToAnnotations;
-
- vector<int> primaryFields;
- int exclusiveField = 0;
- int defaultState = INT_MAX;
- int triggerStateReset = INT_MAX;
- bool nested = true;
-
- int uidField = 0;
-
- AtomDecl();
- AtomDecl(const AtomDecl& that);
- AtomDecl(int code, const string& name, const string& message);
- ~AtomDecl();
-
- inline bool operator<(const AtomDecl& that) const {
- return (code == that.code) ? (name < that.name) : (code < that.code);
- }
-};
-
-using AtomDeclSet = set<shared_ptr<AtomDecl>, SharedComparator>;
-
-// Maps a field number to a set of atoms that have annotation(s) for their field with that field
-// number.
-using FieldNumberToAtomDeclSet = map<int, AtomDeclSet>;
-
-using SignatureInfoMap = map<vector<java_type_t>, FieldNumberToAtomDeclSet>;
-
-struct Atoms {
- SignatureInfoMap signatureInfoMap;
- AtomDeclSet decls;
- AtomDeclSet non_chained_decls;
- SignatureInfoMap nonChainedSignatureInfoMap;
-};
-
-/**
- * Gather the information about the atoms. Returns the number of errors.
- */
-int collate_atoms(const Descriptor* descriptor, const string& moduleName, Atoms* atoms);
-int collate_atom(const Descriptor* atom, AtomDecl* atomDecl, vector<java_type_t>* signature);
-
-} // namespace stats_log_api_gen
-} // namespace android
-
-#endif // ANDROID_STATS_LOG_API_GEN_COLLATION_H
diff --git a/tools/stats_log_api_gen/OWNERS b/tools/stats_log_api_gen/OWNERS
deleted file mode 100644
index 41a0c95..0000000
--- a/tools/stats_log_api_gen/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-yro@google.com
diff --git a/tools/stats_log_api_gen/java_writer.cpp b/tools/stats_log_api_gen/java_writer.cpp
deleted file mode 100644
index f4c937c..0000000
--- a/tools/stats_log_api_gen/java_writer.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (C) 2019, 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 "java_writer.h"
-
-#include "java_writer_q.h"
-#include "utils.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-static int write_java_q_logger_class(FILE* out, const SignatureInfoMap& signatureInfoMap,
- const AtomDecl& attributionDecl) {
- fprintf(out, "\n");
- fprintf(out, " // Write logging helper methods for statsd in Q and earlier.\n");
- fprintf(out, " private static class QLogger {\n");
-
- write_java_q_logging_constants(out, " ");
-
- // Print Q write methods.
- fprintf(out, "\n");
- fprintf(out, " // Write methods.\n");
- write_java_methods_q_schema(out, signatureInfoMap, attributionDecl, " ");
-
- fprintf(out, " }\n");
- return 0;
-}
-
-static void write_java_annotation_constants(FILE* out) {
- fprintf(out, " // Annotation constants.\n");
-
- for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
- fprintf(out, " public static final byte %s = %hhu;\n", name.c_str(), id);
- }
- fprintf(out, "\n");
-}
-
-static void write_annotations(FILE* out, int argIndex,
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet) {
- FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
- fieldNumberToAtomDeclSet.find(argIndex);
- if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
- return;
- }
- const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
- for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
- const string atomConstant = make_constant_name(atomDecl->name);
- fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
- const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
- int resetState = -1;
- int defaultState = -1;
- for (const shared_ptr<Annotation>& annotation : annotations) {
- const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
- switch (annotation->type) {
- case ANNOTATION_TYPE_INT:
- if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
- resetState = annotation->value.intValue;
- } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
- defaultState = annotation->value.intValue;
- } else {
- fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
- annotationConstant.c_str(), annotation->value.intValue);
- }
- break;
- case ANNOTATION_TYPE_BOOL:
- fprintf(out, " builder.addBooleanAnnotation(%s, %s);\n",
- annotationConstant.c_str(),
- annotation->value.boolValue ? "true" : "false");
- break;
- default:
- break;
- }
- }
- if (defaultState != -1 && resetState != -1) {
- const string& annotationConstant =
- ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
- fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
- fprintf(out, " builder.addIntAnnotation(%s, %d);\n",
- annotationConstant.c_str(), defaultState);
- fprintf(out, " }\n");
- }
- fprintf(out, " }\n");
- }
-}
-
-static int write_java_methods(FILE* out, const SignatureInfoMap& signatureInfoMap,
- const AtomDecl& attributionDecl, const bool supportQ) {
- for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
- // Print method signature.
- fprintf(out, " public static void write(int code");
- const vector<java_type_t>& signature = signatureInfoMapIt->first;
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
- chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> valueMap");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ") {\n");
-
- // Print method body.
- string indent("");
- if (supportQ) {
- fprintf(out, " if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n");
- indent = " ";
- }
-
- // Start StatsEvent.Builder.
- fprintf(out,
- "%s final StatsEvent.Builder builder = "
- "StatsEvent.newBuilder();\n",
- indent.c_str());
-
- // Write atom code.
- fprintf(out, "%s builder.setAtomId(code);\n", indent.c_str());
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet);
-
- // Write the args.
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s builder.writeBoolean(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s builder.writeInt(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, "%s builder.writeFloat(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s builder.writeLong(arg%d);\n", indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s builder.writeString(arg%d);\n", indent.c_str(),
- argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- "%s builder.writeByteArray(null == arg%d ? new byte[0] : "
- "arg%d);\n",
- indent.c_str(), argIndex, argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- fprintf(out, "%s builder.writeAttributionChain(\n", indent.c_str());
- fprintf(out, "%s null == %s ? new int[0] : %s,\n",
- indent.c_str(), uidName, uidName);
- fprintf(out, "%s null == %s ? new String[0] : %s);\n",
- indent.c_str(), tagName, tagName);
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- fprintf(out, "\n");
- fprintf(out, "%s // Write KeyValuePairs.\n", indent.c_str());
- fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out, "%s final int key = valueMap.keyAt(i);\n",
- indent.c_str());
- fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out,
- "%s intMap = new "
- "android.util.SparseIntArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s intMap.put(key, (Integer) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Long) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new "
- "android.util.SparseLongArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s longMap.put(key, (Long) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof String) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s stringMap.put(key, (String) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Float) {\n",
- indent.c_str());
- fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s floatMap.put(key, (Float) value);\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out,
- "%s builder.writeKeyValuePairs("
- "intMap, longMap, stringMap, floatMap);\n",
- indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet);
- argIndex++;
- }
-
- fprintf(out, "\n");
- fprintf(out, "%s builder.usePooledBuffer();\n", indent.c_str());
- fprintf(out, "%s StatsLog.write(builder.build());\n", indent.c_str());
-
- // Add support for writing using Q schema if this is not the default module.
- if (supportQ) {
- fprintf(out, " } else {\n");
- fprintf(out, " QLogger.write(code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out, ", %s, %s", uidName, tagName);
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- // Module logging does not yet support key value pair.
- fprintf(stderr, "Module logging does not yet support key value pair.\n");
- return 1;
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, " }\n"); // if
- }
-
- fprintf(out, " }\n"); // method
- fprintf(out, "\n");
- }
- return 0;
-}
-
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& javaClass, const string& javaPackage, const bool supportQ,
- const bool supportWorkSource) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package %s;\n", javaPackage.c_str());
- fprintf(out, "\n");
- fprintf(out, "\n");
- if (supportQ) {
- fprintf(out, "import android.os.Build;\n");
- fprintf(out, "import android.os.SystemClock;\n");
- }
-
- fprintf(out, "import android.util.StatsEvent;\n");
- fprintf(out, "import android.util.StatsLog;\n");
-
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * Utility class for logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "public class %s {\n", javaClass.c_str());
-
- write_java_atom_codes(out, atoms);
- write_java_enum_values(out, atoms);
- write_java_annotation_constants(out);
-
- int errors = 0;
-
- // Print write methods.
- fprintf(out, " // Write methods\n");
- errors += write_java_methods(out, atoms.signatureInfoMap, attributionDecl, supportQ);
- errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
- if (supportWorkSource) {
- errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
- }
-
- if (supportQ) {
- errors += write_java_q_logger_class(out, atoms.signatureInfoMap, attributionDecl);
- }
-
- fprintf(out, "}\n");
-
- return errors;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer.h b/tools/stats_log_api_gen/java_writer.h
deleted file mode 100644
index 8b3b505..0000000
--- a/tools/stats_log_api_gen/java_writer.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2019, 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 <stdio.h>
-#include <string.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "Collation.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-int write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& javaClass, const string& javaPackage, const bool supportQ,
- const bool supportWorkSource);
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
deleted file mode 100644
index d21e270..0000000
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2019, 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 "java_writer_q.h"
-
-#include "utils.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-void write_java_q_logging_constants(FILE* out, const string& indent) {
- fprintf(out, "%s// Payload limits.\n", indent.c_str());
- fprintf(out, "%sprivate static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n", indent.c_str());
- fprintf(out,
- "%sprivate static final int MAX_EVENT_PAYLOAD = "
- "LOGGER_ENTRY_MAX_PAYLOAD - 4;\n",
- indent.c_str());
-
- // Value types. Must match with EventLog.java and log.h.
- fprintf(out, "\n");
- fprintf(out, "%s// Value types.\n", indent.c_str());
- fprintf(out, "%sprivate static final byte INT_TYPE = 0;\n", indent.c_str());
- fprintf(out, "%sprivate static final byte LONG_TYPE = 1;\n", indent.c_str());
- fprintf(out, "%sprivate static final byte STRING_TYPE = 2;\n", indent.c_str());
- fprintf(out, "%sprivate static final byte LIST_TYPE = 3;\n", indent.c_str());
- fprintf(out, "%sprivate static final byte FLOAT_TYPE = 4;\n", indent.c_str());
-
- // Size of each value type.
- // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for
- // the value.
- fprintf(out, "\n");
- fprintf(out, "%s// Size of each value type.\n", indent.c_str());
- fprintf(out, "%sprivate static final int INT_TYPE_SIZE = 5;\n", indent.c_str());
- fprintf(out, "%sprivate static final int FLOAT_TYPE_SIZE = 5;\n", indent.c_str());
- // Longs take 9 bytes, 1 for the type and 8 for the value.
- fprintf(out, "%sprivate static final int LONG_TYPE_SIZE = 9;\n", indent.c_str());
- // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the
- // length.
- fprintf(out, "%sprivate static final int STRING_TYPE_OVERHEAD = 5;\n", indent.c_str());
- fprintf(out, "%sprivate static final int LIST_TYPE_OVERHEAD = 2;\n", indent.c_str());
-}
-
-int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
- const AtomDecl& attributionDecl, const string& indent) {
- int requiredHelpers = 0;
- for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
- // Print method signature.
- vector<java_type_t> signature = signatureInfoMapIt->first;
- fprintf(out, "%spublic static void write(int code", indent.c_str());
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s", java_type_name(chainField.javaType),
- chainField.name.c_str());
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> valueMap");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ") {\n");
-
- // Calculate the size of the buffer.
- fprintf(out, "%s // Initial overhead of the list, timestamp, and atom tag.\n",
- indent.c_str());
- fprintf(out,
- "%s int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + "
- "INT_TYPE_SIZE;\n",
- indent.c_str());
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- case JAVA_TYPE_INT:
- case JAVA_TYPE_FLOAT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s needed += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_LONG:
- // Longs take 9 bytes, 1 for the type and 8 for the value.
- fprintf(out, "%s needed += LONG_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_STRING:
- // Strings take 5 metadata bytes + length of byte encoded string.
- fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
- fprintf(out, "%s arg%d = \"\";\n", indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out,
- "%s byte[] arg%dBytes = "
- "arg%d.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- // Byte arrays take 5 metadata bytes + length of byte array.
- fprintf(out, "%s if (arg%d == null) {\n", indent.c_str(), argIndex);
- fprintf(out, "%s arg%d = new byte[0];\n", indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s needed += STRING_TYPE_OVERHEAD + arg%d.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- // Null checks on the params.
- fprintf(out, "%s if (%s == null) {\n", indent.c_str(), uidName);
- fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), uidName,
- java_type_name(attributionDecl.fields.front().javaType));
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s if (%s == null) {\n", indent.c_str(), tagName);
- fprintf(out, "%s %s = new %s[0];\n", indent.c_str(), tagName,
- java_type_name(attributionDecl.fields.back().javaType));
- fprintf(out, "%s }\n", indent.c_str());
-
- // First check that the lengths of the uid and tag arrays are the
- // same.
- fprintf(out, "%s if (%s.length != %s.length) {\n", indent.c_str(), uidName,
- tagName);
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s int attrSize = LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(),
- tagName);
- fprintf(out, "%s String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
- indent.c_str(), argIndex, tagName, tagName);
- fprintf(out,
- "%s int str%dlen = "
- "str%d.getBytes(java.nio.charset.StandardCharsets.UTF_8)."
- "length;\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out,
- "%s attrSize += "
- "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + "
- "str%dlen;\n",
- indent.c_str(), argIndex);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s needed += attrSize;\n", indent.c_str());
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR: {
- fprintf(out, "%s // Calculate bytes needed by Key Value Pairs.\n",
- indent.c_str());
- fprintf(out, "%s final int count = valueMap.size();\n", indent.c_str());
- fprintf(out, "%s android.util.SparseIntArray intMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseLongArray longMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<String> stringMap = null;\n",
- indent.c_str());
- fprintf(out, "%s android.util.SparseArray<Float> floatMap = null;\n",
- indent.c_str());
- fprintf(out, "%s int keyValuePairSize = LIST_TYPE_OVERHEAD;\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < count; i++) {\n", indent.c_str());
- fprintf(out, "%s final int key = valueMap.keyAt(i);\n", indent.c_str());
- fprintf(out, "%s final Object value = valueMap.valueAt(i);\n",
- indent.c_str());
- fprintf(out, "%s if (value instanceof Integer) {\n", indent.c_str());
- fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out, "%s + INT_TYPE_SIZE + INT_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out, "%s if (null == intMap) {\n", indent.c_str());
- fprintf(out, "%s intMap = new android.util.SparseIntArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s intMap.put(key, (Integer) value);\n",
- indent.c_str());
- fprintf(out, "%s } else if (value instanceof Long) {\n", indent.c_str());
- fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out, "%s + INT_TYPE_SIZE + LONG_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out, "%s if (null == longMap) {\n", indent.c_str());
- fprintf(out,
- "%s longMap = new "
- "android.util.SparseLongArray();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s longMap.put(key, (Long) value);\n", indent.c_str());
- fprintf(out, "%s } else if (value instanceof String) {\n",
- indent.c_str());
- fprintf(out,
- "%s final String str = (value == null) ? \"\" : "
- "(String) value;\n",
- indent.c_str());
- fprintf(out,
- "%s final int len = "
- "str.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;\n",
- indent.c_str());
- fprintf(out,
- "%s keyValuePairSize += LIST_TYPE_OVERHEAD + "
- "INT_TYPE_SIZE\n",
- indent.c_str());
- fprintf(out, "%s + STRING_TYPE_OVERHEAD + len;\n",
- indent.c_str());
- fprintf(out, "%s if (null == stringMap) {\n", indent.c_str());
- fprintf(out,
- "%s stringMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s stringMap.put(key, str);\n", indent.c_str());
- fprintf(out, "%s } else if (value instanceof Float) {\n",
- indent.c_str());
- fprintf(out, "%s keyValuePairSize += LIST_TYPE_OVERHEAD\n",
- indent.c_str());
- fprintf(out, "%s + INT_TYPE_SIZE + FLOAT_TYPE_SIZE;\n",
- indent.c_str());
- fprintf(out, "%s if (null == floatMap) {\n", indent.c_str());
- fprintf(out,
- "%s floatMap = new "
- "android.util.SparseArray<>();\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s floatMap.put(key, (Float) value);\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s needed += keyValuePairSize;\n", indent.c_str());
- break;
- }
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Module logging does not yet support Object and Double.\n");
- return 1;
- }
- argIndex++;
- }
-
- // Now we have the size that is needed. Check for overflow and return if
- // needed.
- fprintf(out, "%s if (needed > MAX_EVENT_PAYLOAD) {\n", indent.c_str());
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
-
- // Create new buffer, and associated data types.
- fprintf(out, "%s byte[] buff = new byte[needed];\n", indent.c_str());
- fprintf(out, "%s int pos = 0;\n", indent.c_str());
-
- // Initialize the buffer with list data type.
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = %zu;\n", indent.c_str(), signature.size() + 2);
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
-
- // Write timestamp.
- fprintf(out, "%s long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n",
- indent.c_str());
- fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyLong(buff, pos + 1, elapsedRealtime);\n", indent.c_str());
- fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
-
- // Write atom code.
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, code);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
-
- // Write the args.
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- switch (*arg) {
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d? 1 : 0);\n", indent.c_str(),
- argIndex);
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d);\n", indent.c_str(),
- argIndex);
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_FLOAT:
- requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
- fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyFloat(buff, pos + 1, arg%d);\n", indent.c_str(),
- argIndex);
- fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyLong(buff, pos + 1, arg%d);\n", indent.c_str(),
- argIndex);
- fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%dBytes.length);\n",
- indent.c_str(), argIndex);
- fprintf(out,
- "%s System.arraycopy("
- "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
- "arg%dBytes.length);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, arg%d.length);\n", indent.c_str(),
- argIndex);
- fprintf(out,
- "%s System.arraycopy("
- "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
- indent.c_str(), argIndex, argIndex);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + arg%d.length;\n",
- indent.c_str(), argIndex);
- break;
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- fprintf(out, "%s writeAttributionChain(buff, pos, %s, %s);\n",
- indent.c_str(), uidName, tagName);
- fprintf(out, "%s pos += attrSize;\n", indent.c_str());
- break;
- }
- case JAVA_TYPE_KEY_VALUE_PAIR:
- requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
- requiredHelpers |= JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS;
- fprintf(out,
- "%s writeKeyValuePairs(buff, pos, (byte) count, intMap, "
- "longMap, "
- "stringMap, floatMap);\n",
- indent.c_str());
- fprintf(out, "%s pos += keyValuePairSize;\n", indent.c_str());
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE.
- fprintf(stderr, "Object and Double are not supported in module logging");
- return 1;
- }
- argIndex++;
- }
-
- fprintf(out, "%s StatsLog.writeRaw(buff, pos);\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
- }
-
- write_java_helpers_for_q_schema_methods(out, attributionDecl, requiredHelpers, indent);
-
- return 0;
-}
-
-void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
- const int requiredHelpers, const string& indent) {
- fprintf(out, "\n");
- fprintf(out, "%s// Helper methods for copying primitives\n", indent.c_str());
- fprintf(out, "%sprivate static void copyInt(byte[] buff, int pos, int val) {\n",
- indent.c_str());
- fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str());
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
-
- fprintf(out, "%sprivate static void copyLong(byte[] buff, int pos, long val) {\n",
- indent.c_str());
- fprintf(out, "%s buff[pos] = (byte) (val);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) (val >> 8);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 2] = (byte) (val >> 16);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 3] = (byte) (val >> 24);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 4] = (byte) (val >> 32);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 5] = (byte) (val >> 40);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 6] = (byte) (val >> 48);\n", indent.c_str());
- fprintf(out, "%s buff[pos + 7] = (byte) (val >> 56);\n", indent.c_str());
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
-
- if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) {
- fprintf(out, "%sprivate static void copyFloat(byte[] buff, int pos, float val) {\n",
- indent.c_str());
- fprintf(out, "%s copyInt(buff, pos, Float.floatToIntBits(val));\n", indent.c_str());
- fprintf(out, "%s return;\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
- }
-
- if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
- fprintf(out, "%sprivate static void writeAttributionChain(byte[] buff, int pos",
- indent.c_str());
- for (auto chainField : attributionDecl.fields) {
- fprintf(out, ", %s[] %s", java_type_name(chainField.javaType), chainField.name.c_str());
- }
- fprintf(out, ") {\n");
-
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
-
- // Write the first list begin.
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) (%s.length);\n", indent.c_str(), tagName);
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
-
- // Iterate through the attribution chain and write the nodes.
- fprintf(out, "%s for (int i = 0; i < %s.length; i++) {\n", indent.c_str(), tagName);
- // Write the list begin.
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = %lu;\n", indent.c_str(),
- attributionDecl.fields.size());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
-
- // Write the uid.
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, %s[i]);\n", indent.c_str(), uidName);
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
-
- // Write the tag.
- fprintf(out, "%s String %sStr = (%s[i] == null) ? \"\" : %s[i];\n", indent.c_str(),
- tagName, tagName, tagName);
- fprintf(out,
- "%s byte[] %sByte = "
- "%sStr.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
- indent.c_str(), tagName, tagName);
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, %sByte.length);\n", indent.c_str(), tagName);
- fprintf(out,
- "%s System.arraycopy("
- "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
- indent.c_str(), tagName, tagName);
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", indent.c_str(),
- tagName);
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
- }
-
- if (requiredHelpers & JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS) {
- fprintf(out,
- "%sprivate static void writeKeyValuePairs(byte[] buff, int pos, "
- "byte numPairs,\n",
- indent.c_str());
- fprintf(out, "%s final android.util.SparseIntArray intMap,\n", indent.c_str());
- fprintf(out, "%s final android.util.SparseLongArray longMap,\n", indent.c_str());
- fprintf(out, "%s final android.util.SparseArray<String> stringMap,\n",
- indent.c_str());
- fprintf(out, "%s final android.util.SparseArray<Float> floatMap) {\n",
- indent.c_str());
-
- // Start list of lists.
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) numPairs;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
-
- // Write integers.
- fprintf(out, "%s final int intMapSize = null == intMap ? 0 : intMap.size();\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < intMapSize; i++) {\n", indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s final int key = intMap.keyAt(i);\n", indent.c_str());
- fprintf(out, "%s final int value = intMap.valueAt(i);\n", indent.c_str());
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, value);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
-
- // Write longs.
- fprintf(out, "%s final int longMapSize = null == longMap ? 0 : longMap.size();\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < longMapSize; i++) {\n", indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s final int key = longMap.keyAt(i);\n", indent.c_str());
- fprintf(out, "%s final long value = longMap.valueAt(i);\n", indent.c_str());
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s buff[pos] = LONG_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyLong(buff, pos + 1, value);\n", indent.c_str());
- fprintf(out, "%s pos += LONG_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
-
- // Write Strings.
- fprintf(out,
- "%s final int stringMapSize = null == stringMap ? 0 : "
- "stringMap.size();\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < stringMapSize; i++) {\n", indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s final int key = stringMap.keyAt(i);\n", indent.c_str());
- fprintf(out, "%s final String value = stringMap.valueAt(i);\n", indent.c_str());
- fprintf(out,
- "%s final byte[] valueBytes = "
- "value.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n",
- indent.c_str());
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s buff[pos] = STRING_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, valueBytes.length);\n", indent.c_str());
- fprintf(out,
- "%s System.arraycopy("
- "valueBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, "
- "valueBytes.length);\n",
- indent.c_str());
- fprintf(out, "%s pos += STRING_TYPE_OVERHEAD + valueBytes.length;\n",
- indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
-
- // Write floats.
- fprintf(out,
- "%s final int floatMapSize = null == floatMap ? 0 : "
- "floatMap.size();\n",
- indent.c_str());
- fprintf(out, "%s for (int i = 0; i < floatMapSize; i++) {\n", indent.c_str());
- fprintf(out, "%s buff[pos] = LIST_TYPE;\n", indent.c_str());
- fprintf(out, "%s buff[pos + 1] = (byte) 2;\n", indent.c_str());
- fprintf(out, "%s pos += LIST_TYPE_OVERHEAD;\n", indent.c_str());
- fprintf(out, "%s final int key = floatMap.keyAt(i);\n", indent.c_str());
- fprintf(out, "%s final float value = floatMap.valueAt(i);\n", indent.c_str());
- fprintf(out, "%s buff[pos] = INT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyInt(buff, pos + 1, key);\n", indent.c_str());
- fprintf(out, "%s pos += INT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s buff[pos] = FLOAT_TYPE;\n", indent.c_str());
- fprintf(out, "%s copyFloat(buff, pos + 1, value);\n", indent.c_str());
- fprintf(out, "%s pos += FLOAT_TYPE_SIZE;\n", indent.c_str());
- fprintf(out, "%s }\n", indent.c_str());
- fprintf(out, "%s}\n", indent.c_str());
- fprintf(out, "\n");
- }
-}
-
-// This method is called in main.cpp to generate StatsLog for modules that's
-// compatible with Q at compile-time.
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& javaClass,
- const string& javaPackage, const bool supportWorkSource) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package %s;\n", javaPackage.c_str());
- fprintf(out, "\n");
- fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
- fprintf(out, "\n");
- fprintf(out, "import android.util.StatsLog;\n");
- fprintf(out, "import android.os.SystemClock;\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * Utility class for logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "public class %s {\n", javaClass.c_str());
-
- write_java_q_logging_constants(out, " ");
-
- write_java_atom_codes(out, atoms);
-
- write_java_enum_values(out, atoms);
-
- int errors = 0;
- // Print write methods
- fprintf(out, " // Write methods\n");
- errors += write_java_methods_q_schema(out, atoms.signatureInfoMap, attributionDecl, " ");
- errors += write_java_non_chained_methods(out, atoms.nonChainedSignatureInfoMap);
- if (supportWorkSource) {
- errors += write_java_work_source_methods(out, atoms.signatureInfoMap);
- }
-
- fprintf(out, "}\n");
-
- return errors;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
deleted file mode 100644
index c511a84..0000000
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2019, 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 <stdio.h>
-#include <string.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "Collation.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-void write_java_q_logging_constants(FILE* out, const string& indent);
-
-int write_java_methods_q_schema(FILE* out, const SignatureInfoMap& signatureInfoMap,
- const AtomDecl& attributionDecl, const string& indent);
-
-void write_java_helpers_for_q_schema_methods(FILE* out, const AtomDecl& attributionDecl,
- const int requiredHelpers, const string& indent);
-
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const string& javaClass,
- const string& javaPackage, const bool supportWorkSource);
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
deleted file mode 100644
index 416dfdd..0000000
--- a/tools/stats_log_api_gen/main.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-
-#include <getopt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "Collation.h"
-#include "frameworks/proto_logging/stats/atoms.pb.h"
-#include "java_writer.h"
-#include "java_writer_q.h"
-#include "native_writer.h"
-#include "utils.h"
-
-using namespace google::protobuf;
-using namespace std;
-
-namespace android {
-namespace stats_log_api_gen {
-
-using android::os::statsd::Atom;
-
-static void print_usage() {
- fprintf(stderr, "usage: stats-log-api-gen OPTIONS\n");
- fprintf(stderr, "\n");
- fprintf(stderr, "OPTIONS\n");
- fprintf(stderr, " --cpp FILENAME the header file to output for write helpers\n");
- fprintf(stderr, " --header FILENAME the cpp file to output for write helpers\n");
- fprintf(stderr, " --help this message\n");
- fprintf(stderr, " --java FILENAME the java file to output\n");
- fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
- fprintf(stderr,
- " --namespace COMMA,SEP,NAMESPACE required for cpp/header with "
- "module\n");
- fprintf(stderr,
- " comma separated namespace of "
- "the files\n");
- fprintf(stderr,
- " --importHeader NAME required for cpp/jni to say which header to "
- "import "
- "for write helpers\n");
- fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
- fprintf(stderr, " required for java with module\n");
- fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
- fprintf(stderr, " Optional for Java with module.\n");
- fprintf(stderr, " Default is \"StatsLogInternal\"\n");
- fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
- fprintf(stderr,
- " --worksource Include support for logging WorkSource "
- "objects.\n");
- fprintf(stderr,
- " --compileQ Include compile-time support for Android Q "
- "(Java only).\n");
-}
-
-/**
- * Do the argument parsing and execute the tasks.
- */
-static int run(int argc, char const* const* argv) {
- string cppFilename;
- string headerFilename;
- string javaFilename;
- string javaPackage;
- string javaClass;
-
- string moduleName = DEFAULT_MODULE_NAME;
- string cppNamespace = DEFAULT_CPP_NAMESPACE;
- string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
- bool supportQ = false;
- bool supportWorkSource = false;
- bool compileQ = false;
-
- int index = 1;
- while (index < argc) {
- if (0 == strcmp("--help", argv[index])) {
- print_usage();
- return 0;
- } else if (0 == strcmp("--cpp", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- cppFilename = argv[index];
- } else if (0 == strcmp("--header", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- headerFilename = argv[index];
- } else if (0 == strcmp("--java", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- javaFilename = argv[index];
- } else if (0 == strcmp("--module", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- moduleName = argv[index];
- } else if (0 == strcmp("--namespace", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- cppNamespace = argv[index];
- } else if (0 == strcmp("--importHeader", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- cppHeaderImport = argv[index];
- } else if (0 == strcmp("--javaPackage", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- javaPackage = argv[index];
- } else if (0 == strcmp("--javaClass", argv[index])) {
- index++;
- if (index >= argc) {
- print_usage();
- return 1;
- }
- javaClass = argv[index];
- } else if (0 == strcmp("--supportQ", argv[index])) {
- supportQ = true;
- } else if (0 == strcmp("--worksource", argv[index])) {
- supportWorkSource = true;
- } else if (0 == strcmp("--compileQ", argv[index])) {
- compileQ = true;
- }
-
- index++;
- }
-
- if (cppFilename.size() == 0 && headerFilename.size() == 0 && javaFilename.size() == 0) {
- print_usage();
- return 1;
- }
-
- if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
- // Support for Q schema is not needed for default module.
- fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
- return 1;
- }
-
- if (supportQ && compileQ) {
- // Runtime Q support is redundant if compile-time Q support is required.
- fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
- return 1;
- }
-
- // Collate the parameters
- Atoms atoms;
- int errorCount = collate_atoms(Atom::descriptor(), moduleName, &atoms);
- if (errorCount != 0) {
- return 1;
- }
-
- AtomDecl attributionDecl;
- vector<java_type_t> attributionSignature;
- collate_atom(android::os::statsd::AttributionNode::descriptor(), &attributionDecl,
- &attributionSignature);
-
- // Write the .cpp file
- if (cppFilename.size() != 0) {
- FILE* out = fopen(cppFilename.c_str(), "w");
- if (out == NULL) {
- fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
- return 1;
- }
- // If this is for a specific module, the namespace must also be provided.
- if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
- fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
- return 1;
- }
- // If this is for a specific module, the header file to import must also be
- // provided.
- if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
- fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
- return 1;
- }
- errorCount = android::stats_log_api_gen::write_stats_log_cpp(
- out, atoms, attributionDecl, cppNamespace, cppHeaderImport, supportQ);
- fclose(out);
- }
-
- // Write the .h file
- if (headerFilename.size() != 0) {
- FILE* out = fopen(headerFilename.c_str(), "w");
- if (out == NULL) {
- fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
- return 1;
- }
- // If this is for a specific module, the namespace must also be provided.
- if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
- fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
- }
- errorCount = android::stats_log_api_gen::write_stats_log_header(out, atoms, attributionDecl,
- cppNamespace);
- fclose(out);
- }
-
- // Write the .java file
- if (javaFilename.size() != 0) {
- if (javaClass.size() == 0) {
- fprintf(stderr, "Must supply --javaClass if supplying a Java filename");
- return 1;
- }
-
- if (javaPackage.size() == 0) {
- fprintf(stderr, "Must supply --javaPackage if supplying a Java filename");
- return 1;
- }
-
- if (moduleName.size() == 0) {
- fprintf(stderr, "Must supply --module if supplying a Java filename");
- return 1;
- }
-
- FILE* out = fopen(javaFilename.c_str(), "w");
- if (out == NULL) {
- fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
- return 1;
- }
-
- if (compileQ) {
- errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
- out, atoms, attributionDecl, javaClass, javaPackage, supportWorkSource);
- } else {
- errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl, javaClass, javaPackage, supportQ,
- supportWorkSource);
- }
-
- fclose(out);
- }
-
- return errorCount;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
-
-/**
- * Main.
- */
-int main(int argc, char const* const* argv) {
- GOOGLE_PROTOBUF_VERIFY_VERSION;
-
- return android::stats_log_api_gen::run(argc, argv);
-}
diff --git a/tools/stats_log_api_gen/native_writer.cpp b/tools/stats_log_api_gen/native_writer.cpp
deleted file mode 100644
index 0c6c009..0000000
--- a/tools/stats_log_api_gen/native_writer.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-/*
- * Copyright (C) 2019, 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 "native_writer.h"
-
-#include "utils.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-static void write_native_annotation_constants(FILE* out) {
- fprintf(out, "// Annotation constants.\n");
-
- for (const auto& [id, name] : ANNOTATION_ID_CONSTANTS) {
- fprintf(out, "const uint8_t %s = %hhu;\n", name.c_str(), id);
- }
- fprintf(out, "\n");
-}
-
-static void write_annotations(FILE* out, int argIndex,
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet,
- const string& methodPrefix, const string& methodSuffix) {
- FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt =
- fieldNumberToAtomDeclSet.find(argIndex);
- if (fieldNumberToAtomDeclSet.end() == fieldNumberToAtomDeclSetIt) {
- return;
- }
- const AtomDeclSet& atomDeclSet = fieldNumberToAtomDeclSetIt->second;
- for (const shared_ptr<AtomDecl>& atomDecl : atomDeclSet) {
- const string atomConstant = make_constant_name(atomDecl->name);
- fprintf(out, " if (%s == code) {\n", atomConstant.c_str());
- const AnnotationSet& annotations = atomDecl->fieldNumberToAnnotations.at(argIndex);
- int resetState = -1;
- int defaultState = -1;
- for (const shared_ptr<Annotation>& annotation : annotations) {
- const string& annotationConstant = ANNOTATION_ID_CONSTANTS.at(annotation->annotationId);
- switch (annotation->type) {
- case ANNOTATION_TYPE_INT:
- if (ANNOTATION_ID_TRIGGER_STATE_RESET == annotation->annotationId) {
- resetState = annotation->value.intValue;
- } else if (ANNOTATION_ID_DEFAULT_STATE == annotation->annotationId) {
- defaultState = annotation->value.intValue;
- } else {
- fprintf(out, " %saddInt32Annotation(%s%s, %d);\n",
- methodPrefix.c_str(), methodSuffix.c_str(),
- annotationConstant.c_str(), annotation->value.intValue);
- }
- break;
- case ANNOTATION_TYPE_BOOL:
- // TODO(b/151786433): Write annotation constant name instead of
- // annotation id literal.
- fprintf(out, " %saddBoolAnnotation(%s%s, %s);\n", methodPrefix.c_str(),
- methodSuffix.c_str(), annotationConstant.c_str(),
- annotation->value.boolValue ? "true" : "false");
- break;
- default:
- break;
- }
- }
- if (defaultState != -1 && resetState != -1) {
- const string& annotationConstant =
- ANNOTATION_ID_CONSTANTS.at(ANNOTATION_ID_TRIGGER_STATE_RESET);
- fprintf(out, " if (arg%d == %d) {\n", argIndex, resetState);
- fprintf(out, " %saddInt32Annotation(%s%s, %d);\n", methodPrefix.c_str(),
- methodSuffix.c_str(), annotationConstant.c_str(), defaultState);
- fprintf(out, " }\n");
- }
- fprintf(out, " }\n");
- }
-}
-
-static int write_native_stats_write_methods(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl, const bool supportQ) {
- fprintf(out, "\n");
- for (auto signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signatureInfoMapIt != atoms.signatureInfoMap.end(); signatureInfoMapIt++) {
- vector<java_type_t> signature = signatureInfoMapIt->first;
- const FieldNumberToAtomDeclSet& fieldNumberToAtomDeclSet = signatureInfoMapIt->second;
- // Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
- continue;
- }
- write_native_method_signature(out, "int stats_write", signature, attributionDecl, " {");
-
- int argIndex = 1;
- if (supportQ) {
- fprintf(out, " StatsEventCompat event;\n");
- fprintf(out, " event.setAtomId(code);\n");
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "event.", "");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out, " event.writeAttributionChain(%s, %s_length, %s);\n",
- uidName, uidName, tagName);
- break;
- }
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out, " event.writeByteArray(arg%d.arg, arg%d.arg_length);\n",
- argIndex, argIndex);
- break;
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, " event.writeBool(arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_INT: // Fall through.
- case JAVA_TYPE_ENUM:
- fprintf(out, " event.writeInt32(arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, " event.writeFloat(arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, " event.writeInt64(arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, " event.writeString(arg%d);\n", argIndex);
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS.
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "event.", "");
- argIndex++;
- }
- fprintf(out, " return event.writeToSocket();\n");
- } else {
- fprintf(out, " AStatsEvent* event = AStatsEvent_obtain();\n");
- fprintf(out, " AStatsEvent_setAtomId(event, code);\n");
- write_annotations(out, ATOM_ID_FIELD_NUMBER, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- for (vector<java_type_t>::const_iterator arg = signature.begin();
- arg != signature.end(); arg++) {
- switch (*arg) {
- case JAVA_TYPE_ATTRIBUTION_CHAIN: {
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out,
- " AStatsEvent_writeAttributionChain(event, "
- "reinterpret_cast<const uint32_t*>(%s), %s.data(), "
- "static_cast<uint8_t>(%s_length));\n",
- uidName, tagName, uidName);
- break;
- }
- case JAVA_TYPE_BYTE_ARRAY:
- fprintf(out,
- " AStatsEvent_writeByteArray(event, "
- "reinterpret_cast<const uint8_t*>(arg%d.arg), "
- "arg%d.arg_length);\n",
- argIndex, argIndex);
- break;
- case JAVA_TYPE_BOOLEAN:
- fprintf(out, " AStatsEvent_writeBool(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_INT: // Fall through.
- case JAVA_TYPE_ENUM:
- fprintf(out, " AStatsEvent_writeInt32(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_FLOAT:
- fprintf(out, " AStatsEvent_writeFloat(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_LONG:
- fprintf(out, " AStatsEvent_writeInt64(event, arg%d);\n", argIndex);
- break;
- case JAVA_TYPE_STRING:
- fprintf(out, " AStatsEvent_writeString(event, arg%d);\n", argIndex);
- break;
- default:
- // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIRS
- fprintf(stderr, "Encountered unsupported type.");
- return 1;
- }
- write_annotations(out, argIndex, fieldNumberToAtomDeclSet, "AStatsEvent_",
- "event, ");
- argIndex++;
- }
- fprintf(out, " const int ret = AStatsEvent_write(event);\n");
- fprintf(out, " AStatsEvent_release(event);\n");
- fprintf(out, " return ret;\n");
- }
- fprintf(out, "}\n\n");
- }
- return 0;
-}
-
-static void write_native_stats_write_non_chained_methods(FILE* out, const Atoms& atoms,
- const AtomDecl& attributionDecl) {
- fprintf(out, "\n");
- for (auto signature_it = atoms.nonChainedSignatureInfoMap.begin();
- signature_it != atoms.nonChainedSignatureInfoMap.end(); signature_it++) {
- vector<java_type_t> signature = signature_it->first;
- // Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
- continue;
- }
-
- write_native_method_signature(out, "int stats_write_non_chained", signature,
- attributionDecl, " {");
-
- vector<java_type_t> newSignature;
-
- // First two args form the attribution node so size goes down by 1.
- newSignature.reserve(signature.size() - 1);
-
- // First arg is Attribution Chain.
- newSignature.push_back(JAVA_TYPE_ATTRIBUTION_CHAIN);
-
- // Followed by the originial signature except the first 2 args.
- newSignature.insert(newSignature.end(), signature.begin() + 2, signature.end());
-
- const char* uidName = attributionDecl.fields.front().name.c_str();
- const char* tagName = attributionDecl.fields.back().name.c_str();
- fprintf(out, " const int32_t* %s = &arg1;\n", uidName);
- fprintf(out, " const size_t %s_length = 1;\n", uidName);
- fprintf(out, " const std::vector<char const*> %s(1, arg2);\n", tagName);
- fprintf(out, " return ");
- write_native_method_call(out, "stats_write", newSignature, attributionDecl, 2);
-
- fprintf(out, "}\n\n");
- }
-}
-
-static void write_native_method_header(FILE* out, const string& methodName,
- const SignatureInfoMap& signatureInfoMap,
- const AtomDecl& attributionDecl) {
- for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
- vector<java_type_t> signature = signatureInfoMapIt->first;
-
- // Key value pairs not supported in native.
- if (find(signature.begin(), signature.end(), JAVA_TYPE_KEY_VALUE_PAIR) != signature.end()) {
- continue;
- }
- write_native_method_signature(out, methodName, signature, attributionDecl, ";");
- }
-}
-
-int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& cppNamespace, const string& importHeader,
- const bool supportQ) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
-
- fprintf(out, "#include <%s>\n", importHeader.c_str());
- if (supportQ) {
- fprintf(out, "#include <StatsEventCompat.h>\n");
- } else {
- fprintf(out, "#include <stats_event.h>\n");
- }
-
- fprintf(out, "\n");
- write_namespace(out, cppNamespace);
-
- write_native_stats_write_methods(out, atoms, attributionDecl, supportQ);
- write_native_stats_write_non_chained_methods(out, atoms, attributionDecl);
-
- // Print footer
- fprintf(out, "\n");
- write_closing_namespace(out, cppNamespace);
-
- return 0;
-}
-
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& cppNamespace) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "#pragma once\n");
- fprintf(out, "\n");
- fprintf(out, "#include <stdint.h>\n");
- fprintf(out, "#include <vector>\n");
- fprintf(out, "#include <map>\n");
- fprintf(out, "#include <set>\n");
- fprintf(out, "\n");
-
- write_namespace(out, cppNamespace);
- fprintf(out, "\n");
- fprintf(out, "/*\n");
- fprintf(out, " * API For logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "\n");
-
- write_native_atom_constants(out, atoms, attributionDecl);
-
- // Print constants for the enum values.
- fprintf(out, "//\n");
- fprintf(out, "// Constants for enum values\n");
- fprintf(out, "//\n\n");
- for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
- atomIt++) {
- for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
- field != (*atomIt)->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, "// Values for %s.%s\n", (*atomIt)->message.c_str(),
- field->name.c_str());
- for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
- fprintf(out, "const int32_t %s__%s__%s = %d;\n",
- make_constant_name((*atomIt)->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(), value->first);
- }
- fprintf(out, "\n");
- }
- }
- }
-
- write_native_annotation_constants(out);
-
- fprintf(out, "struct BytesField {\n");
- fprintf(out,
- " BytesField(char const* array, size_t len) : arg(array), "
- "arg_length(len) {}\n");
- fprintf(out, " char const* arg;\n");
- fprintf(out, " size_t arg_length;\n");
- fprintf(out, "};\n");
- fprintf(out, "\n");
-
- // Print write methods
- fprintf(out, "//\n");
- fprintf(out, "// Write methods\n");
- fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write", atoms.signatureInfoMap, attributionDecl);
-
- fprintf(out, "//\n");
- fprintf(out, "// Write flattened methods\n");
- fprintf(out, "//\n");
- write_native_method_header(out, "int stats_write_non_chained", atoms.nonChainedSignatureInfoMap,
- attributionDecl);
-
- fprintf(out, "\n");
- write_closing_namespace(out, cppNamespace);
-
- return 0;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/native_writer.h b/tools/stats_log_api_gen/native_writer.h
deleted file mode 100644
index 264d4db..0000000
--- a/tools/stats_log_api_gen/native_writer.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019, 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 <stdio.h>
-#include <string.h>
-
-#include "Collation.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-int write_stats_log_cpp(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& cppNamespace, const string& importHeader,
- const bool supportQ);
-
-int write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl,
- const string& cppNamespace);
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
deleted file mode 100644
index a3ea785..0000000
--- a/tools/stats_log_api_gen/test.proto
+++ /dev/null
@@ -1,215 +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.
- */
-
-syntax = "proto2";
-
-import "frameworks/proto_logging/stats/atoms.proto";
-import "frameworks/proto_logging/stats/atom_field_options.proto";
-
-package android.stats_log_api_gen;
-
-message IntAtom {
- optional int32 field1 = 1;
-}
-
-message AnotherIntAtom {
- optional int32 field1 = 1;
-}
-
-message OutOfOrderAtom {
- optional int32 field2 = 2;
- optional int32 field1 = 1;
-}
-
-enum AnEnum {
- VALUE0 = 0;
- VALUE1 = 1;
-}
-
-message AllTypesAtom {
- repeated android.os.statsd.AttributionNode attribution_chain = 1;
- optional float float_field = 2;
- optional int64 int64_field = 3;
- optional uint64 uint64_field = 4;
- optional int32 int32_field = 5;
- optional fixed64 fixed64_field = 6;
- optional fixed32 fixed32_field = 7;
- optional bool bool_field = 8;
- optional string string_field = 9;
- optional uint32 uint32_field = 10;
- optional AnEnum enum_field = 11;
- optional sfixed32 sfixed32_field = 12;
- optional sfixed64 sfixed64_field = 13;
- optional sint32 sint32_field = 14;
- optional sint64 sint64_field = 15;
-}
-
-message Event {
- oneof event {
- OutOfOrderAtom out_of_order_atom = 2;
- IntAtom int_atom = 1;
- AnotherIntAtom another_int_atom = 3;
- AllTypesAtom all_types_atom = 4;
- }
-}
-
-message BadTypesAtom {
- optional IntAtom bad_int_atom = 1;
- optional bytes bad_bytes = 2;
- repeated int32 repeated_field = 3;
- optional double double_field = 4;
-}
-
-message BadTypesEvent {
- oneof event {
- BadTypesAtom bad_types_atom = 1;
- }
-}
-
-message BadSkippedFieldSingleAtom {
- optional int32 field2 = 2;
-}
-
-message BadSkippedFieldSingle {
- oneof event {
- BadSkippedFieldSingleAtom bad = 1;
- }
-}
-
-message BadSkippedFieldMultipleAtom {
- optional int32 field1 = 1;
- optional int32 field3 = 3;
- optional int32 field5 = 5;
-}
-
-message BadSkippedFieldMultiple {
- oneof event {
- BadSkippedFieldMultipleAtom bad = 1;
- }
-}
-
-message BadAttributionNodePositionAtom {
- optional int32 field1 = 1;
- repeated android.os.statsd.AttributionNode attribution = 2;
-}
-
-message BadAttributionNodePosition {
- oneof event { BadAttributionNodePositionAtom bad = 1; }
-}
-
-message GoodEventWithBinaryFieldAtom {
- oneof event { GoodBinaryFieldAtom field1 = 1; }
-}
-
-message ComplexField {
- optional string str = 1;
-}
-
-message GoodBinaryFieldAtom {
- optional int32 field1 = 1;
- optional ComplexField bf = 2 [(android.os.statsd.log_mode) = MODE_BYTES];
-}
-
-message BadEventWithBinaryFieldAtom {
- oneof event { BadBinaryFieldAtom field1 = 1; }
-}
-
-message BadBinaryFieldAtom {
- optional int32 field1 = 1;
- optional ComplexField bf = 2;
-}
-
-message BadStateAtoms {
- oneof event {
- BadStateAtom1 bad1 = 1;
- BadStateAtom2 bad2 = 2;
- BadStateAtom3 bad3 = 3;
- }
-}
-
-message GoodStateAtoms {
- oneof event {
- GoodStateAtom1 good1 = 1;
- GoodStateAtom2 good2 = 2;
- }
-}
-
-// The atom has only primary field but no exclusive state field.
-message BadStateAtom1 {
- optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
-}
-
-// Only primative types can be annotated.
-message BadStateAtom2 {
- repeated android.os.statsd.AttributionNode attribution = 1
- [(android.os.statsd.state_field_option).primary_field = true];
- optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-// Having 2 exclusive state field in the atom means the atom is badly designed.
-// E.g., putting bluetooth state and wifi state in the same atom.
-message BadStateAtom3 {
- optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
- optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
- optional int32 state2 = 3 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-message GoodStateAtom1 {
- optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
- optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-// Atoms can have exclusive state field, but no primary field. That means
-// the state is globally exclusive (e.g., DisplayState).
-message GoodStateAtom2 {
- optional int32 uid = 1;
- optional int32 state = 2 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-// We can have more than one primary fields. That means their combination is a
-// primary key.
-message GoodStateAtom3 {
- optional int32 uid = 1 [(android.os.statsd.state_field_option).primary_field = true];
- optional int32 tid = 2 [(android.os.statsd.state_field_option).primary_field = true];
- optional int32 state = 3 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-message ModuleOneAtom {
- optional int32 field = 1 [(android.os.statsd.is_uid) = true];
-}
-
-message ModuleTwoAtom {
- optional int32 field = 1;
-}
-
-message ModuleOneAndTwoAtom {
- optional int32 field = 1 [(android.os.statsd.state_field_option).exclusive_state = true];
-}
-
-message NoModuleAtom {
- optional string field = 1;
-}
-
-message ModuleAtoms {
- oneof event {
- ModuleOneAtom module_one_atom = 1 [(android.os.statsd.module) = "module1"];
- ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.module) = "module2"];
- ModuleOneAndTwoAtom module_one_and_two_atom = 3 [
- (android.os.statsd.module) = "module1", (android.os.statsd.module) = "module2"
- ];
- NoModuleAtom no_module_atom = 4;
- }
-}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
deleted file mode 100644
index dbae588..0000000
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ /dev/null
@@ -1,369 +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.
- */
-
-#include <gtest/gtest.h>
-#include <stdio.h>
-
-#include "Collation.h"
-#include "frameworks/base/tools/stats_log_api_gen/test.pb.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using std::map;
-using std::set;
-using std::vector;
-
-/**
- * Return whether the map contains a vector of the elements provided.
- */
-static bool map_contains_vector(const SignatureInfoMap& s, int count, ...) {
- va_list args;
- vector<java_type_t> v;
-
- va_start(args, count);
- for (int i = 0; i < count; i++) {
- v.push_back((java_type_t)va_arg(args, int));
- }
- va_end(args);
-
- return s.find(v) != s.end();
-}
-
-/**
- * Expect that the provided map contains the elements provided.
- */
-#define EXPECT_MAP_CONTAINS_SIGNATURE(s, ...) \
- do { \
- int count = sizeof((int[]){__VA_ARGS__}) / sizeof(int); \
- EXPECT_TRUE(map_contains_vector(s, count, __VA_ARGS__)); \
- } while (0)
-
-/** Expects that the provided atom has no enum values for any field. */
-#define EXPECT_NO_ENUM_FIELD(atom) \
- do { \
- for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
- field != atom->fields.end(); field++) { \
- EXPECT_TRUE(field->enumValues.empty()); \
- } \
- } while (0)
-
-/** Expects that exactly one specific field has expected enum values. */
-#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \
- do { \
- for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
- field != atom->fields.end(); field++) { \
- if (field->name == field_name) { \
- EXPECT_EQ(field->enumValues, values); \
- } else { \
- EXPECT_TRUE(field->enumValues.empty()); \
- } \
- } \
- } while (0)
-
-/**
- * Test a correct collation, with all the types.
- */
-TEST(CollationTest, CollateStats) {
- Atoms atoms;
- int errorCount = collate_atoms(Event::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(0, errorCount);
- EXPECT_EQ(3ul, atoms.signatureInfoMap.size());
-
- // IntAtom, AnotherIntAtom
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
-
- // OutOfOrderAtom
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT, JAVA_TYPE_INT);
-
- // AllTypesAtom
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap,
- JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
- JAVA_TYPE_FLOAT, // float
- JAVA_TYPE_LONG, // int64
- JAVA_TYPE_LONG, // uint64
- JAVA_TYPE_INT, // int32
- JAVA_TYPE_LONG, // fixed64
- JAVA_TYPE_INT, // fixed32
- JAVA_TYPE_BOOLEAN, // bool
- JAVA_TYPE_STRING, // string
- JAVA_TYPE_INT, // uint32
- JAVA_TYPE_INT, // AnEnum
- JAVA_TYPE_INT, // sfixed32
- JAVA_TYPE_LONG, // sfixed64
- JAVA_TYPE_INT, // sint32
- JAVA_TYPE_LONG // sint64
- );
-
- EXPECT_EQ(4ul, atoms.decls.size());
-
- AtomDeclSet::const_iterator atomIt = atoms.decls.begin();
- EXPECT_EQ(1, (*atomIt)->code);
- EXPECT_EQ("int_atom", (*atomIt)->name);
- EXPECT_EQ("IntAtom", (*atomIt)->message);
- EXPECT_NO_ENUM_FIELD((*atomIt));
- atomIt++;
-
- EXPECT_EQ(2, (*atomIt)->code);
- EXPECT_EQ("out_of_order_atom", (*atomIt)->name);
- EXPECT_EQ("OutOfOrderAtom", (*atomIt)->message);
- EXPECT_NO_ENUM_FIELD((*atomIt));
- atomIt++;
-
- EXPECT_EQ(3, (*atomIt)->code);
- EXPECT_EQ("another_int_atom", (*atomIt)->name);
- EXPECT_EQ("AnotherIntAtom", (*atomIt)->message);
- EXPECT_NO_ENUM_FIELD((*atomIt));
- atomIt++;
-
- EXPECT_EQ(4, (*atomIt)->code);
- EXPECT_EQ("all_types_atom", (*atomIt)->name);
- EXPECT_EQ("AllTypesAtom", (*atomIt)->message);
- map<int, string> enumValues;
- enumValues[0] = "VALUE0";
- enumValues[1] = "VALUE1";
- EXPECT_HAS_ENUM_FIELD((*atomIt), "enum_field", enumValues);
- atomIt++;
-
- EXPECT_EQ(atoms.decls.end(), atomIt);
-}
-
-/**
- * Test that event class that contains stuff other than the atoms is rejected.
- */
-TEST(CollationTest, NonMessageTypeFails) {
- Atoms atoms;
- int errorCount = collate_atoms(IntAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(1, errorCount);
-}
-
-/**
- * Test that atoms that have non-primitive types or repeated fields are
- * rejected.
- */
-TEST(CollationTest, FailOnBadTypes) {
- Atoms atoms;
- int errorCount = collate_atoms(BadTypesEvent::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(4, errorCount);
-}
-
-/**
- * Test that atoms that skip field numbers (in the first position) are rejected.
- */
-TEST(CollationTest, FailOnSkippedFieldsSingle) {
- Atoms atoms;
- int errorCount =
- collate_atoms(BadSkippedFieldSingle::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(1, errorCount);
-}
-
-/**
- * Test that atoms that skip field numbers (not in the first position, and
- * multiple times) are rejected.
- */
-TEST(CollationTest, FailOnSkippedFieldsMultiple) {
- Atoms atoms;
- int errorCount =
- collate_atoms(BadSkippedFieldMultiple::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(2, errorCount);
-}
-
-/**
- * Test that atoms that have an attribution chain not in the first position are
- * rejected.
- */
-TEST(CollationTest, FailBadAttributionNodePosition) {
- Atoms atoms;
- int errorCount =
- collate_atoms(BadAttributionNodePosition::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(1, errorCount);
-}
-
-TEST(CollationTest, FailOnBadStateAtomOptions) {
- Atoms atoms;
- int errorCount = collate_atoms(BadStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
-
- EXPECT_EQ(3, errorCount);
-}
-
-TEST(CollationTest, PassOnGoodStateAtomOptions) {
- Atoms atoms;
- int errorCount = collate_atoms(GoodStateAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_EQ(0, errorCount);
-}
-
-TEST(CollationTest, PassOnGoodBinaryFieldAtom) {
- Atoms atoms;
- int errorCount =
- collate_atoms(GoodEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_EQ(0, errorCount);
-}
-
-TEST(CollationTest, FailOnBadBinaryFieldAtom) {
- Atoms atoms;
- int errorCount =
- collate_atoms(BadEventWithBinaryFieldAtom::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_TRUE(errorCount > 0);
-}
-
-TEST(CollationTest, PassOnLogFromModuleAtom) {
- Atoms atoms;
- int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_EQ(errorCount, 0);
- EXPECT_EQ(atoms.decls.size(), 4ul);
-}
-
-TEST(CollationTest, RecognizeModuleAtom) {
- Atoms atoms;
- int errorCount = collate_atoms(ModuleAtoms::descriptor(), DEFAULT_MODULE_NAME, &atoms);
- EXPECT_EQ(errorCount, 0);
- EXPECT_EQ(atoms.decls.size(), 4ul);
- EXPECT_EQ(atoms.signatureInfoMap.size(), 2u);
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_STRING);
-
- SignatureInfoMap::const_iterator signatureInfoMapIt;
- const vector<java_type_t>* signature;
- const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet;
- FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt;
- const AtomDeclSet* atomDeclSet;
- AtomDeclSet::const_iterator atomDeclSetIt;
- AtomDecl* atomDecl;
- FieldNumberToAnnotations* fieldNumberToAnnotations;
- FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt;
- const AnnotationSet* annotationSet;
- AnnotationSet::const_iterator annotationSetIt;
- Annotation* annotation;
-
- signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signature = &(signatureInfoMapIt->first);
- fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
- EXPECT_EQ(1ul, signature->size());
- EXPECT_EQ(JAVA_TYPE_INT, signature->at(0));
- EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size());
- fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin();
- EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first);
- atomDeclSet = &fieldNumberToAtomDeclSetIt->second;
- EXPECT_EQ(2ul, atomDeclSet->size());
- atomDeclSetIt = atomDeclSet->begin();
- atomDecl = atomDeclSetIt->get();
- EXPECT_EQ(1, atomDecl->code);
- fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
- fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
- EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
- annotationSet = &fieldNumberToAnnotationsIt->second;
- EXPECT_EQ(1ul, annotationSet->size());
- annotationSetIt = annotationSet->begin();
- annotation = annotationSetIt->get();
- EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId);
- EXPECT_EQ(1, annotation->atomId);
- EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
- EXPECT_TRUE(annotation->value.boolValue);
-
- atomDeclSetIt++;
- atomDecl = atomDeclSetIt->get();
- EXPECT_EQ(3, atomDecl->code);
- fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
- fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
- EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
- annotationSet = &fieldNumberToAnnotationsIt->second;
- EXPECT_EQ(1ul, annotationSet->size());
- annotationSetIt = annotationSet->begin();
- annotation = annotationSetIt->get();
- EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId);
- EXPECT_EQ(3, annotation->atomId);
- EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
- EXPECT_TRUE(annotation->value.boolValue);
-
- signatureInfoMapIt++;
- signature = &signatureInfoMapIt->first;
- fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
- EXPECT_EQ(1ul, signature->size());
- EXPECT_EQ(JAVA_TYPE_STRING, signature->at(0));
- EXPECT_EQ(0ul, fieldNumberToAtomDeclSet->size());
-}
-
-TEST(CollationTest, RecognizeModule1Atom) {
- Atoms atoms;
- const string moduleName = "module1";
- int errorCount = collate_atoms(ModuleAtoms::descriptor(), moduleName, &atoms);
- EXPECT_EQ(errorCount, 0);
- EXPECT_EQ(atoms.decls.size(), 2ul);
- EXPECT_EQ(atoms.signatureInfoMap.size(), 1u);
- EXPECT_MAP_CONTAINS_SIGNATURE(atoms.signatureInfoMap, JAVA_TYPE_INT);
-
- SignatureInfoMap::const_iterator signatureInfoMapIt;
- const vector<java_type_t>* signature;
- const FieldNumberToAtomDeclSet* fieldNumberToAtomDeclSet;
- FieldNumberToAtomDeclSet::const_iterator fieldNumberToAtomDeclSetIt;
- const AtomDeclSet* atomDeclSet;
- AtomDeclSet::const_iterator atomDeclSetIt;
- AtomDecl* atomDecl;
- FieldNumberToAnnotations* fieldNumberToAnnotations;
- FieldNumberToAnnotations::const_iterator fieldNumberToAnnotationsIt;
- const AnnotationSet* annotationSet;
- AnnotationSet::const_iterator annotationSetIt;
- Annotation* annotation;
-
- signatureInfoMapIt = atoms.signatureInfoMap.begin();
- signature = &(signatureInfoMapIt->first);
- fieldNumberToAtomDeclSet = &signatureInfoMapIt->second;
- EXPECT_EQ(1ul, signature->size());
- EXPECT_EQ(JAVA_TYPE_INT, signature->at(0));
- EXPECT_EQ(1ul, fieldNumberToAtomDeclSet->size());
- fieldNumberToAtomDeclSetIt = fieldNumberToAtomDeclSet->begin();
- EXPECT_EQ(1, fieldNumberToAtomDeclSetIt->first);
- atomDeclSet = &fieldNumberToAtomDeclSetIt->second;
- EXPECT_EQ(2ul, atomDeclSet->size());
- atomDeclSetIt = atomDeclSet->begin();
- atomDecl = atomDeclSetIt->get();
- EXPECT_EQ(1, atomDecl->code);
- fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
- fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
- EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
- annotationSet = &fieldNumberToAnnotationsIt->second;
- EXPECT_EQ(1ul, annotationSet->size());
- annotationSetIt = annotationSet->begin();
- annotation = annotationSetIt->get();
- EXPECT_EQ(ANNOTATION_ID_IS_UID, annotation->annotationId);
- EXPECT_EQ(1, annotation->atomId);
- EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
- EXPECT_TRUE(annotation->value.boolValue);
-
- atomDeclSetIt++;
- atomDecl = atomDeclSetIt->get();
- EXPECT_EQ(3, atomDecl->code);
- fieldNumberToAnnotations = &atomDecl->fieldNumberToAnnotations;
- fieldNumberToAnnotationsIt = fieldNumberToAnnotations->find(1);
- EXPECT_NE(fieldNumberToAnnotations->end(), fieldNumberToAnnotationsIt);
- annotationSet = &fieldNumberToAnnotationsIt->second;
- EXPECT_EQ(1ul, annotationSet->size());
- annotationSetIt = annotationSet->begin();
- annotation = annotationSetIt->get();
- EXPECT_EQ(ANNOTATION_ID_EXCLUSIVE_STATE, annotation->annotationId);
- EXPECT_EQ(3, annotation->atomId);
- EXPECT_EQ(ANNOTATION_TYPE_BOOL, annotation->type);
- EXPECT_TRUE(annotation->value.boolValue);
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/utils.cpp b/tools/stats_log_api_gen/utils.cpp
deleted file mode 100644
index abb8913..0000000
--- a/tools/stats_log_api_gen/utils.cpp
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright (C) 2019, 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 "utils.h"
-
-#include "android-base/strings.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-static void build_non_chained_decl_map(const Atoms& atoms,
- std::map<int, AtomDeclSet::const_iterator>* decl_map) {
- for (AtomDeclSet::const_iterator atomIt = atoms.non_chained_decls.begin();
- atomIt != atoms.non_chained_decls.end(); atomIt++) {
- decl_map->insert(std::make_pair((*atomIt)->code, atomIt));
- }
-}
-
-/**
- * Turn lower and camel case into upper case with underscores.
- */
-string make_constant_name(const string& str) {
- string result;
- const int N = str.size();
- bool underscore_next = false;
- for (int i = 0; i < N; i++) {
- char c = str[i];
- if (c >= 'A' && c <= 'Z') {
- if (underscore_next) {
- result += '_';
- underscore_next = false;
- }
- } else if (c >= 'a' && c <= 'z') {
- c = 'A' + c - 'a';
- underscore_next = true;
- } else if (c == '_') {
- underscore_next = false;
- }
- result += c;
- }
- return result;
-}
-
-const char* cpp_type_name(java_type_t type) {
- switch (type) {
- case JAVA_TYPE_BOOLEAN:
- return "bool";
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- return "int32_t";
- case JAVA_TYPE_LONG:
- return "int64_t";
- case JAVA_TYPE_FLOAT:
- return "float";
- case JAVA_TYPE_DOUBLE:
- return "double";
- case JAVA_TYPE_STRING:
- return "char const*";
- case JAVA_TYPE_BYTE_ARRAY:
- return "const BytesField&";
- default:
- return "UNKNOWN";
- }
-}
-
-const char* java_type_name(java_type_t type) {
- switch (type) {
- case JAVA_TYPE_BOOLEAN:
- return "boolean";
- case JAVA_TYPE_INT:
- case JAVA_TYPE_ENUM:
- return "int";
- case JAVA_TYPE_LONG:
- return "long";
- case JAVA_TYPE_FLOAT:
- return "float";
- case JAVA_TYPE_DOUBLE:
- return "double";
- case JAVA_TYPE_STRING:
- return "java.lang.String";
- case JAVA_TYPE_BYTE_ARRAY:
- return "byte[]";
- default:
- return "UNKNOWN";
- }
-}
-
-// Native
-// Writes namespaces for the cpp and header files, returning the number of
-// namespaces written.
-void write_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
- for (string cppNamespace : cppNamespaceVec) {
- fprintf(out, "namespace %s {\n", cppNamespace.c_str());
- }
-}
-
-// Writes namespace closing brackets for cpp and header files.
-void write_closing_namespace(FILE* out, const string& cppNamespaces) {
- vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
- for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
- fprintf(out, "} // namespace %s\n", it->c_str());
- }
-}
-
-static void write_cpp_usage(FILE* out, const string& method_name, const string& atom_code_name,
- const shared_ptr<AtomDecl> atom, const AtomDecl& attributionDecl) {
- fprintf(out, " * Usage: %s(StatsLog.%s", method_name.c_str(), atom_code_name.c_str());
-
- for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
- chainField.name.c_str());
- } else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType), chainField.name.c_str(),
- chainField.name.c_str());
- }
- }
- } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out,
- ", const std::map<int, int32_t>& %s_int"
- ", const std::map<int, int64_t>& %s_long"
- ", const std::map<int, char const*>& %s_str"
- ", const std::map<int, float>& %s_float",
- field->name.c_str(), field->name.c_str(), field->name.c_str(),
- field->name.c_str());
- } else {
- fprintf(out, ", %s %s", cpp_type_name(field->javaType), field->name.c_str());
- }
- }
- fprintf(out, ");\n");
-}
-
-void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl) {
- fprintf(out, "/**\n");
- fprintf(out, " * Constants for atom codes.\n");
- fprintf(out, " */\n");
- fprintf(out, "enum {\n");
-
- std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
- build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
-
- size_t i = 0;
- // Print atom constants
- for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
- atomIt++) {
- string constant = make_constant_name((*atomIt)->name);
- fprintf(out, "\n");
- fprintf(out, " /**\n");
- fprintf(out, " * %s %s\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
- write_cpp_usage(out, "stats_write", constant, *atomIt, attributionDecl);
-
- auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
- if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
- write_cpp_usage(out, "stats_write_non_chained", constant, *non_chained_decl->second,
- attributionDecl);
- }
- fprintf(out, " */\n");
- char const* const comma = (i == atoms.decls.size() - 1) ? "" : ",";
- fprintf(out, " %s = %d%s\n", constant.c_str(), (*atomIt)->code, comma);
- i++;
- }
- fprintf(out, "\n");
- fprintf(out, "};\n");
- fprintf(out, "\n");
-}
-
-void write_native_method_signature(FILE* out, const string& methodName,
- const vector<java_type_t>& signature,
- const AtomDecl& attributionDecl, const string& closer) {
- fprintf(out, "%s(int32_t code", methodName.c_str());
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", const std::vector<%s>& %s", cpp_type_name(chainField.javaType),
- chainField.name.c_str());
- } else {
- fprintf(out, ", const %s* %s, size_t %s_length",
- cpp_type_name(chainField.javaType), chainField.name.c_str(),
- chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out,
- ", const std::map<int, int32_t>& arg%d_1, "
- "const std::map<int, int64_t>& arg%d_2, "
- "const std::map<int, char const*>& arg%d_3, "
- "const std::map<int, float>& arg%d_4",
- argIndex, argIndex, argIndex, argIndex);
- } else {
- fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ")%s\n", closer.c_str());
-}
-
-void write_native_method_call(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
- int argIndex) {
- fprintf(out, "%s(code", methodName.c_str());
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- for (auto chainField : attributionDecl.fields) {
- if (chainField.javaType == JAVA_TYPE_STRING) {
- fprintf(out, ", %s", chainField.name.c_str());
- } else {
- fprintf(out, ", %s, %s_length", chainField.name.c_str(),
- chainField.name.c_str());
- }
- }
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", arg%d_1, arg%d_2, arg%d_3, arg%d_4", argIndex, argIndex, argIndex,
- argIndex);
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
-}
-
-// Java
-void write_java_atom_codes(FILE* out, const Atoms& atoms) {
- fprintf(out, " // Constants for atom codes.\n");
-
- std::map<int, AtomDeclSet::const_iterator> atom_code_to_non_chained_decl_map;
- build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
-
- // Print constants for the atom codes.
- for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
- atomIt++) {
- string constant = make_constant_name((*atomIt)->name);
- fprintf(out, "\n");
- fprintf(out, " /**\n");
- fprintf(out, " * %s %s<br>\n", (*atomIt)->message.c_str(), (*atomIt)->name.c_str());
- write_java_usage(out, "write", constant, **atomIt);
- auto non_chained_decl = atom_code_to_non_chained_decl_map.find((*atomIt)->code);
- if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
- write_java_usage(out, "write_non_chained", constant, **(non_chained_decl->second));
- }
- fprintf(out, " */\n");
- fprintf(out, " public static final int %s = %d;\n", constant.c_str(), (*atomIt)->code);
- }
- fprintf(out, "\n");
-}
-
-void write_java_enum_values(FILE* out, const Atoms& atoms) {
- fprintf(out, " // Constants for enum values.\n\n");
- for (AtomDeclSet::const_iterator atomIt = atoms.decls.begin(); atomIt != atoms.decls.end();
- atomIt++) {
- for (vector<AtomField>::const_iterator field = (*atomIt)->fields.begin();
- field != (*atomIt)->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, " // Values for %s.%s\n", (*atomIt)->message.c_str(),
- field->name.c_str());
- for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
- fprintf(out, " public static final int %s__%s__%s = %d;\n",
- make_constant_name((*atomIt)->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(), value->first);
- }
- fprintf(out, "\n");
- }
- }
- }
-}
-
-void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
- const AtomDecl& atom) {
- fprintf(out, " * Usage: StatsLog.%s(StatsLog.%s", method_name.c_str(),
- atom_code_name.c_str());
- for (vector<AtomField>::const_iterator field = atom.fields.begin(); field != atom.fields.end();
- field++) {
- if (field->javaType == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- fprintf(out, ", android.os.WorkSource workSource");
- } else if (field->javaType == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(out, ", android.util.SparseArray<Object> value_map");
- } else if (field->javaType == JAVA_TYPE_BYTE_ARRAY) {
- fprintf(out, ", byte[] %s", field->name.c_str());
- } else {
- fprintf(out, ", %s %s", java_type_name(field->javaType), field->name.c_str());
- }
- }
- fprintf(out, ");<br>\n");
-}
-
-int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
- for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
- // Print method signature.
- fprintf(out, " public static void write_non_chained(int code");
- vector<java_type_t> signature = signatureInfoMapIt->first;
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- fprintf(stderr, "Non chained signatures should not have attribution chains.\n");
- return 1;
- } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
- fprintf(stderr, "Module logging does not yet support key value pair.\n");
- return 1;
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ") {\n");
-
- fprintf(out, " write(code");
- argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- // First two args are uid and tag of attribution chain.
- if (argIndex == 1) {
- fprintf(out, ", new int[] {arg%d}", argIndex);
- } else if (argIndex == 2) {
- fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- argIndex++;
- }
- fprintf(out, ");\n");
- fprintf(out, " }\n");
- fprintf(out, "\n");
- }
- return 0;
-}
-
-int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap) {
- fprintf(out, " // WorkSource methods.\n");
- for (auto signatureInfoMapIt = signatureInfoMap.begin();
- signatureInfoMapIt != signatureInfoMap.end(); signatureInfoMapIt++) {
- vector<java_type_t> signature = signatureInfoMapIt->first;
- // Determine if there is Attribution in this signature.
- int attributionArg = -1;
- int argIndexMax = 0;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- argIndexMax++;
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- if (attributionArg > -1) {
- fprintf(stderr, "An atom contains multiple AttributionNode fields.\n");
- fprintf(stderr, "This is not supported. Aborting WorkSource method writing.\n");
- fprintf(out,
- "\n// Invalid for WorkSource: more than one attribution "
- "chain.\n");
- return 1;
- }
- attributionArg = argIndexMax;
- }
- }
- if (attributionArg < 0) {
- continue;
- }
-
- fprintf(out, "\n");
- // Method header (signature)
- fprintf(out, " public static void write(int code");
- int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature.begin(); arg != signature.end();
- arg++) {
- if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
- fprintf(out, ", android.os.WorkSource ws");
- } else {
- fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
- }
- argIndex++;
- }
- fprintf(out, ") {\n");
-
- // write_non_chained() component. TODO: Remove when flat uids are no longer
- // needed.
- fprintf(out, " for (int i = 0; i < ws.size(); ++i) {\n");
- fprintf(out, " write_non_chained(code");
- for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
- if (argIndex == attributionArg) {
- fprintf(out, ", ws.getUid(i), ws.getPackageName(i)");
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- }
- fprintf(out, ");\n");
- fprintf(out, " }\n"); // close for-loop
-
- // write() component.
- fprintf(out,
- " java.util.List<android.os.WorkSource.WorkChain> workChains = "
- "ws.getWorkChains();\n");
- fprintf(out, " if (workChains != null) {\n");
- fprintf(out,
- " for (android.os.WorkSource.WorkChain wc : workChains) "
- "{\n");
- fprintf(out, " write(code");
- for (int argIndex = 1; argIndex <= argIndexMax; argIndex++) {
- if (argIndex == attributionArg) {
- fprintf(out, ", wc.getUids(), wc.getTags()");
- } else {
- fprintf(out, ", arg%d", argIndex);
- }
- }
- fprintf(out, ");\n");
- fprintf(out, " }\n"); // close for-loop
- fprintf(out, " }\n"); // close if
- fprintf(out, " }\n"); // close method
- }
- return 0;
-}
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/tools/stats_log_api_gen/utils.h b/tools/stats_log_api_gen/utils.h
deleted file mode 100644
index 73e0cb8..0000000
--- a/tools/stats_log_api_gen/utils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2019, 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 <stdio.h>
-#include <string.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include "Collation.h"
-
-namespace android {
-namespace stats_log_api_gen {
-
-using namespace std;
-
-const string DEFAULT_CPP_NAMESPACE = "android,util";
-const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
-
-const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
-const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
-const int JAVA_MODULE_REQUIRES_KEY_VALUE_PAIRS = 0x04;
-
-const map<AnnotationId, string> ANNOTATION_ID_CONSTANTS = {
- {ANNOTATION_ID_IS_UID, "ANNOTATION_ID_IS_UID"},
- {ANNOTATION_ID_TRUNCATE_TIMESTAMP, "ANNOTATION_ID_TRUNCATE_TIMESTAMP"},
- {ANNOTATION_ID_PRIMARY_FIELD, "ANNOTATION_ID_PRIMARY_FIELD"},
- {ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, "ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID"},
- {ANNOTATION_ID_EXCLUSIVE_STATE, "ANNOTATION_ID_EXCLUSIVE_STATE"},
- {ANNOTATION_ID_TRIGGER_STATE_RESET, "ANNOTATION_ID_TRIGGER_STATE_RESET"},
- {ANNOTATION_ID_STATE_NESTED, "ANNOTATION_ID_STATE_NESTED"}};
-
-string make_constant_name(const string& str);
-
-const char* cpp_type_name(java_type_t type);
-
-const char* java_type_name(java_type_t type);
-
-// Common Native helpers
-void write_namespace(FILE* out, const string& cppNamespaces);
-
-void write_closing_namespace(FILE* out, const string& cppNamespaces);
-
-void write_native_atom_constants(FILE* out, const Atoms& atoms, const AtomDecl& attributionDecl);
-
-void write_native_method_signature(FILE* out, const string& methodName,
- const vector<java_type_t>& signature,
- const AtomDecl& attributionDecl, const string& closer);
-
-void write_native_method_call(FILE* out, const string& methodName,
- const vector<java_type_t>& signature, const AtomDecl& attributionDecl,
- int argIndex = 1);
-
-// Common Java helpers.
-void write_java_atom_codes(FILE* out, const Atoms& atoms);
-
-void write_java_enum_values(FILE* out, const Atoms& atoms);
-
-void write_java_usage(FILE* out, const string& method_name, const string& atom_code_name,
- const AtomDecl& atom);
-
-int write_java_non_chained_methods(FILE* out, const SignatureInfoMap& signatureInfoMap);
-
-int write_java_work_source_methods(FILE* out, const SignatureInfoMap& signatureInfoMap);
-
-} // namespace stats_log_api_gen
-} // namespace android
diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt
index 75b5e72..4099c27 100644
--- a/wifi/jarjar-rules.txt
+++ b/wifi/jarjar-rules.txt
@@ -21,6 +21,7 @@
rule android.net.ResolverParamsParcel* com.android.wifi.x.@0
rule android.net.RouteInfoParcel* com.android.wifi.x.@0
rule android.net.ScanResultInfoParcelable* com.android.wifi.x.@0
+rule android.net.TcpKeepalivePacketDataParcelable* com.android.wifi.x.@0
rule android.net.TetherConfigParcel* com.android.wifi.x.@0
rule android.net.TetherOffloadRuleParcel* com.android.wifi.x.@0
rule android.net.TetherStatsParcel* com.android.wifi.x.@0
@@ -43,7 +44,6 @@
rule android.net.InterfaceConfiguration* com.android.wifi.x.@0
rule android.net.IpMemoryStore* com.android.wifi.x.@0
rule android.net.NetworkMonitorManager* com.android.wifi.x.@0
-rule android.net.TcpKeepalivePacketData* com.android.wifi.x.@0
rule android.net.NetworkFactory* com.android.wifi.x.@0
rule android.net.ip.IpClientCallbacks* com.android.wifi.x.@0
rule android.net.ip.IpClientManager* com.android.wifi.x.@0