diff options
Diffstat (limited to 'cmds')
36 files changed, 2166 insertions, 232 deletions
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java index 2adbc1f6e1ae..7c30c8b1e1dd 100644 --- a/cmds/am/src/com/android/commands/am/Instrument.java +++ b/cmds/am/src/com/android/commands/am/Instrument.java @@ -17,8 +17,8 @@ package com.android.commands.am; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS; +import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE; import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; -import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; import android.app.IActivityManager; import android.app.IInstrumentationWatcher; @@ -512,7 +512,7 @@ public class Instrument { flags |= INSTR_FLAG_DISABLE_TEST_API_CHECKS; } if (disableIsolatedStorage) { - flags |= INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; + flags |= INSTR_FLAG_DISABLE_ISOLATED_STORAGE; } if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId, abi)) { diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp index ef5c4cec9166..878cef94b674 100644 --- a/cmds/idmap2/Android.bp +++ b/cmds/idmap2/Android.bp @@ -23,9 +23,16 @@ cc_defaults { "misc-*", "readability-*", ], + tidy_checks_as_errors: [ + "modernize-*", + "-modernize-avoid-c-arrays", + "-modernize-use-trailing-return-type", + "android-*", + "misc-*", + "readability-*", + ], tidy_flags: [ "-system-headers", - "-warnings-as-errors=*", ], } @@ -168,13 +175,13 @@ cc_binary { ], host_supported: true, srcs: [ + "idmap2/CommandUtils.cpp", "idmap2/Create.cpp", "idmap2/CreateMultiple.cpp", "idmap2/Dump.cpp", "idmap2/Lookup.cpp", "idmap2/Main.cpp", "idmap2/Scan.cpp", - "idmap2/Verify.cpp", ], target: { android: { diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/CommandUtils.cpp index 9cb67b33e6cf..8f5845bf2e53 100644 --- a/cmds/idmap2/idmap2/Verify.cpp +++ b/cmds/idmap2/idmap2/CommandUtils.cpp @@ -19,30 +19,19 @@ #include <string> #include <vector> -#include "idmap2/CommandLineOptions.h" #include "idmap2/Idmap.h" #include "idmap2/Result.h" #include "idmap2/SysTrace.h" -using android::idmap2::CommandLineOptions; using android::idmap2::Error; using android::idmap2::IdmapHeader; using android::idmap2::Result; using android::idmap2::Unit; -Result<Unit> Verify(const std::vector<std::string>& args) { - SYSTRACE << "Verify " << args; - std::string idmap_path; - - const CommandLineOptions opts = - CommandLineOptions("idmap2 verify") - .MandatoryOption("--idmap-path", "input: path to idmap file to verify", &idmap_path); - - const auto opts_ok = opts.Parse(args); - if (!opts_ok) { - return opts_ok.GetError(); - } - +Result<Unit> Verify(const std::string& idmap_path, const std::string& target_path, + const std::string& overlay_path, PolicyBitmask fulfilled_policies, + bool enforce_overlayable) { + SYSTRACE << "Verify " << idmap_path; std::ifstream fin(idmap_path); const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); fin.close(); @@ -50,7 +39,8 @@ Result<Unit> Verify(const std::vector<std::string>& args) { return Error("failed to parse idmap header"); } - const auto header_ok = header->IsUpToDate(); + const auto header_ok = header->IsUpToDate(target_path.c_str(), overlay_path.c_str(), + fulfilled_policies, enforce_overlayable); if (!header_ok) { return Error(header_ok.GetError(), "idmap not up to date"); } diff --git a/cmds/idmap2/idmap2/CommandUtils.h b/cmds/idmap2/idmap2/CommandUtils.h new file mode 100644 index 000000000000..e717e046d15d --- /dev/null +++ b/cmds/idmap2/idmap2/CommandUtils.h @@ -0,0 +1,29 @@ +/* + * 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 IDMAP2_IDMAP2_COMMAND_UTILS_H_ +#define IDMAP2_IDMAP2_COMMAND_UTILS_H_ + +#include "idmap2/PolicyUtils.h" +#include "idmap2/Result.h" + +android::idmap2::Result<android::idmap2::Unit> Verify(const std::string& idmap_path, + const std::string& target_path, + const std::string& overlay_path, + PolicyBitmask fulfilled_policies, + bool enforce_overlayable); + +#endif // IDMAP2_IDMAP2_COMMAND_UTILS_H_ diff --git a/cmds/idmap2/idmap2/Commands.h b/cmds/idmap2/idmap2/Commands.h index e626738a2895..69eea8d262d2 100644 --- a/cmds/idmap2/idmap2/Commands.h +++ b/cmds/idmap2/idmap2/Commands.h @@ -27,6 +27,5 @@ android::idmap2::Result<android::idmap2::Unit> CreateMultiple(const std::vector< 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); -android::idmap2::Result<android::idmap2::Unit> Verify(const std::vector<std::string>& args); #endif // IDMAP2_IDMAP2_COMMANDS_H_ diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp index 4b70acc2969c..abdfaf4dccab 100644 --- a/cmds/idmap2/idmap2/CreateMultiple.cpp +++ b/cmds/idmap2/idmap2/CreateMultiple.cpp @@ -26,6 +26,7 @@ #include "android-base/stringprintf.h" #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/CommandLineOptions.h" +#include "idmap2/CommandUtils.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" #include "idmap2/Policies.h" @@ -103,7 +104,8 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) { continue; } - if (!Verify(std::vector<std::string>({"--idmap-path", idmap_path}))) { + if (!Verify(idmap_path, target_apk_path, overlay_apk_path, fulfilled_policies, + !ignore_overlayable)) { const std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path); if (!overlay_apk) { LOG(WARNING) << "failed to load apk " << overlay_apk_path.c_str(); diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp index a07e793d9f47..fb093f0f22a4 100644 --- a/cmds/idmap2/idmap2/Main.cpp +++ b/cmds/idmap2/idmap2/Main.cpp @@ -53,9 +53,8 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) { int main(int argc, char** argv) { SYSTRACE << "main"; const NameToFunctionMap commands = { - {"create", Create}, {"create-multiple", CreateMultiple}, - {"dump", Dump}, {"lookup", Lookup}, - {"scan", Scan}, {"verify", Verify}, + {"create", Create}, {"create-multiple", CreateMultiple}, {"dump", Dump}, {"lookup", Lookup}, + {"scan", Scan}, }; if (argc <= 1) { PrintUsage(commands, std::cerr); diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp index da0453216f03..36250450cc74 100644 --- a/cmds/idmap2/idmap2/Scan.cpp +++ b/cmds/idmap2/idmap2/Scan.cpp @@ -27,8 +27,11 @@ #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" @@ -48,6 +51,7 @@ 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; @@ -215,7 +219,15 @@ Result<Unit> Scan(const std::vector<std::string>& args) { std::stringstream stream; for (const auto& overlay : interesting_apks) { - if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}))) { + 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}; diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index a93184ff4787..f95b73f17222 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -33,16 +33,19 @@ #include "idmap2/BinaryStreamVisitor.h" #include "idmap2/FileUtils.h" #include "idmap2/Idmap.h" +#include "idmap2/Result.h" #include "idmap2/SysTrace.h" #include "idmap2/ZipFile.h" #include "utils/String8.h" using android::IPCThreadState; +using android::base::StringPrintf; using android::binder::Status; using android::idmap2::BinaryStreamVisitor; using android::idmap2::GetPackageCrc; using android::idmap2::Idmap; using android::idmap2::IdmapHeader; +using android::idmap2::ZipFile; using android::idmap2::utils::kIdmapCacheDir; using android::idmap2::utils::kIdmapFilePermissionMask; using android::idmap2::utils::UidHasWriteAccessToPath; @@ -66,6 +69,21 @@ PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) { return static_cast<PolicyBitmask>(arg); } +Status GetCrc(const std::string& apk_path, uint32_t* out_crc) { + const auto zip = ZipFile::Open(apk_path); + if (!zip) { + return error(StringPrintf("failed to open apk %s", apk_path.c_str())); + } + + const auto crc = GetPackageCrc(*zip); + if (!crc) { + return error(crc.GetErrorMessage()); + } + + *out_crc = *crc; + return ok(); +} + } // namespace namespace android::os { @@ -98,12 +116,12 @@ Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path, } Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, - const std::string& overlay_apk_path, - int32_t fulfilled_policies ATTRIBUTE_UNUSED, - bool enforce_overlayable ATTRIBUTE_UNUSED, - int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) { + const std::string& overlay_apk_path, int32_t fulfilled_policies, + bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED, + bool* _aidl_return) { SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path; assert(_aidl_return); + const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path); std::ifstream fin(idmap_path); const std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(fin); @@ -113,35 +131,36 @@ Status Idmap2Service::verifyIdmap(const std::string& target_apk_path, return error("failed to parse idmap header"); } - if (strcmp(header->GetTargetPath().data(), target_apk_path.data()) != 0) { - *_aidl_return = false; - return ok(); - } - - if (target_apk_path != kFrameworkPath) { - *_aidl_return = (bool) header->IsUpToDate(); + uint32_t target_crc; + if (target_apk_path == kFrameworkPath && android_crc_) { + target_crc = *android_crc_; } else { - if (!android_crc_) { - // Loading the framework zip can take several milliseconds. Cache the crc of the framework - // resource APK to reduce repeated work during boot. - const auto target_zip = idmap2::ZipFile::Open(target_apk_path); - if (!target_zip) { - return error(base::StringPrintf("failed to open target %s", target_apk_path.c_str())); - } - - const auto target_crc = GetPackageCrc(*target_zip); - if (!target_crc) { - return error(target_crc.GetErrorMessage()); - } - - android_crc_ = *target_crc; + auto target_crc_status = GetCrc(target_apk_path, &target_crc); + if (!target_crc_status.isOk()) { + *_aidl_return = false; + return target_crc_status; + } + + // Loading the framework zip can take several milliseconds. Cache the crc of the framework + // resource APK to reduce repeated work during boot. + if (target_apk_path == kFrameworkPath) { + android_crc_ = target_crc; } + } - *_aidl_return = (bool) header->IsUpToDate(android_crc_.value()); + uint32_t overlay_crc; + auto overlay_crc_status = GetCrc(overlay_apk_path, &overlay_crc); + if (!overlay_crc_status.isOk()) { + *_aidl_return = false; + return overlay_crc_status; } - // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed - return ok(); + auto up_to_date = + header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), target_crc, overlay_crc, + ConvertAidlArgToPolicyBitmask(fulfilled_policies), enforce_overlayable); + + *_aidl_return = static_cast<bool>(up_to_date); + return *_aidl_return ? ok() : error(up_to_date.GetErrorMessage()); } Status Idmap2Service::createIdmap(const std::string& target_apk_path, diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index 77a7b30a230e..0f05592b70f3 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -117,6 +117,14 @@ class IdmapHeader { return overlay_crc_; } + inline uint32_t GetFulfilledPolicies() const { + return fulfilled_policies_; + } + + bool GetEnforceOverlayable() const { + return enforce_overlayable_; + } + inline StringPiece GetTargetPath() const { return StringPiece(target_path_); } @@ -132,8 +140,11 @@ class IdmapHeader { // Invariant: anytime the idmap data encoding is changed, the idmap version // field *must* be incremented. Because of this, we know that if the idmap // header is up-to-date the entire file is up-to-date. - Result<Unit> IsUpToDate() const; - Result<Unit> IsUpToDate(uint32_t target_crc_) const; + Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, + PolicyBitmask fulfilled_policies, bool enforce_overlayable) const; + Result<Unit> IsUpToDate(const char* target_path, const char* overlay_path, uint32_t target_crc, + uint32_t overlay_crc, PolicyBitmask fulfilled_policies, + bool enforce_overlayable) const; void accept(Visitor* v) const; @@ -145,6 +156,8 @@ class IdmapHeader { uint32_t version_; uint32_t target_crc_; uint32_t overlay_crc_; + uint32_t fulfilled_policies_; + bool enforce_overlayable_; char target_path_[kIdmapStringLength]; char overlay_path_[kIdmapStringLength]; std::string debug_info_; diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index 362dcb36007a..255212ad4c66 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -66,6 +66,8 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) { Write32(header.GetVersion()); Write32(header.GetTargetCrc()); Write32(header.GetOverlayCrc()); + Write32(header.GetFulfilledPolicies()); + Write8(static_cast<uint8_t>(header.GetEnforceOverlayable())); WriteString256(header.GetTargetPath()); WriteString256(header.GetOverlayPath()); WriteString(header.GetDebugInfo()); diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 706b842b3b47..23c25a7089de 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -112,14 +112,17 @@ Result<uint32_t> GetPackageCrc(const ZipFile& zip) { std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) { std::unique_ptr<IdmapHeader> idmap_header(new IdmapHeader()); - + uint8_t enforce_overlayable; if (!Read32(stream, &idmap_header->magic_) || !Read32(stream, &idmap_header->version_) || !Read32(stream, &idmap_header->target_crc_) || !Read32(stream, &idmap_header->overlay_crc_) || + !Read32(stream, &idmap_header->fulfilled_policies_) || !Read8(stream, &enforce_overlayable) || !ReadString256(stream, idmap_header->target_path_) || !ReadString256(stream, idmap_header->overlay_path_)) { return nullptr; } + idmap_header->enforce_overlayable_ = static_cast<bool>(enforce_overlayable); + auto debug_str = ReadString(stream); if (!debug_str) { return nullptr; @@ -129,21 +132,37 @@ std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& s return std::move(idmap_header); } -Result<Unit> IdmapHeader::IsUpToDate() const { - const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path_); +Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path, + PolicyBitmask fulfilled_policies, + bool enforce_overlayable) const { + const std::unique_ptr<const ZipFile> target_zip = ZipFile::Open(target_path); if (!target_zip) { - return Error("failed to open target %s", GetTargetPath().to_string().c_str()); + return Error("failed to open target %s", target_path); } - Result<uint32_t> target_crc = GetPackageCrc(*target_zip); + const Result<uint32_t> target_crc = GetPackageCrc(*target_zip); if (!target_crc) { return Error("failed to get target crc"); } - return IsUpToDate(*target_crc); + const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path); + if (!overlay_zip) { + return Error("failed to overlay target %s", overlay_path); + } + + const Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip); + if (!overlay_crc) { + return Error("failed to get overlay crc"); + } + + return IsUpToDate(target_path, overlay_path, *target_crc, *overlay_crc, fulfilled_policies, + enforce_overlayable); } -Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const { +Result<Unit> IdmapHeader::IsUpToDate(const char* target_path, const char* overlay_path, + uint32_t target_crc, uint32_t overlay_crc, + PolicyBitmask fulfilled_policies, + bool enforce_overlayable) const { if (magic_ != kIdmapMagic) { return Error("bad magic: actual 0x%08x, expected 0x%08x", magic_, kIdmapMagic); } @@ -157,19 +176,29 @@ Result<Unit> IdmapHeader::IsUpToDate(uint32_t target_crc) const { target_crc); } - const std::unique_ptr<const ZipFile> overlay_zip = ZipFile::Open(overlay_path_); - if (!overlay_zip) { - return Error("failed to open overlay %s", GetOverlayPath().to_string().c_str()); + if (overlay_crc_ != overlay_crc) { + return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_, + overlay_crc); } - Result<uint32_t> overlay_crc = GetPackageCrc(*overlay_zip); - if (!overlay_crc) { - return Error("failed to get overlay crc"); + if (fulfilled_policies_ != fulfilled_policies) { + return Error("bad fulfilled policies: idmap version 0x%08x, file system version 0x%08x", + fulfilled_policies, fulfilled_policies_); } - if (overlay_crc_ != *overlay_crc) { - return Error("bad overlay crc: idmap version 0x%08x, file system version 0x%08x", overlay_crc_, - *overlay_crc); + if (enforce_overlayable != enforce_overlayable_) { + return Error("bad enforce overlayable: idmap version %s, file system version %s", + enforce_overlayable ? "true" : "false", enforce_overlayable_ ? "true" : "false"); + } + + if (strcmp(target_path, target_path_) != 0) { + return Error("bad target path: idmap version %s, file system version %s", target_path, + target_path_); + } + + if (strcmp(overlay_path, overlay_path_) != 0) { + return Error("bad overlay path: idmap version %s, file system version %s", overlay_path, + overlay_path_); } return Unit{}; @@ -320,6 +349,9 @@ Result<std::unique_ptr<const Idmap>> Idmap::FromApkAssets(const ApkAssets& targe } header->overlay_crc_ = *crc; + header->fulfilled_policies_ = fulfilled_policies; + header->enforce_overlayable_ = enforce_overlayable; + if (target_apk_path.size() > sizeof(header->target_path_)) { return Error("target apk path \"%s\" longer than maximum size %zu", target_apk_path.c_str(), sizeof(header->target_path_)); diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp index 751c60c4add4..3f62a2ae2029 100644 --- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp +++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp @@ -23,10 +23,12 @@ #include "android-base/macros.h" #include "android-base/stringprintf.h" #include "androidfw/ApkAssets.h" +#include "idmap2/PolicyUtils.h" #include "idmap2/ResourceUtils.h" #include "idmap2/Result.h" using android::ApkAssets; +using android::idmap2::policy::PoliciesToDebugString; namespace { @@ -39,9 +41,6 @@ size_t StringSizeWhenEncoded(const std::string& s) { namespace android::idmap2 { -// verbatim copy fomr PrettyPrintVisitor.cpp, move to common utils -#define RESID(pkg, type, entry) (((pkg) << 24) | ((type) << 16) | (entry)) - void RawPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) { } @@ -50,6 +49,9 @@ void RawPrintVisitor::visit(const IdmapHeader& header) { print(header.GetVersion(), "version"); print(header.GetTargetCrc(), "target crc"); print(header.GetOverlayCrc(), "overlay crc"); + print(header.GetFulfilledPolicies(), "fulfilled policies: %s", + PoliciesToDebugString(header.GetFulfilledPolicies()).c_str()); + print(static_cast<uint8_t>(header.GetEnforceOverlayable()), "enforce overlayable"); print(header.GetTargetPath().to_string(), kIdmapStringLength, "target path"); print(header.GetOverlayPath().to_string(), kIdmapStringLength, "overlay path"); print("...", StringSizeWhenEncoded(header.GetDebugInfo()), "debug info"); diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 44acbcaf8ace..34589a1c39dc 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -61,8 +61,7 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package, const ResourceId& target_resource) { static constexpr const PolicyBitmask sDefaultPolicies = PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | - PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | - PolicyFlags::ACTOR_SIGNATURE; + PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE; // If the resource does not have an overlayable definition, allow the resource to be overlaid if // the overlay is preinstalled or signed with the same signature as the target. @@ -292,13 +291,6 @@ Result<ResourceMapping> ResourceMapping::FromApkAssets(const ApkAssets& target_a const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, LogInfo& log_info) { - if (enforce_overlayable) { - log_info.Info(LogMessage() << "fulfilled_policies=" - << ConcatPolicies(BitmaskToPolicies(fulfilled_policies)) - << " enforce_overlayable=" - << (enforce_overlayable ? "true" : "false")); - } - AssetManager2 target_asset_manager; if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true /* invalidate_caches */, false /* filter_incompatible_configs*/)) { diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 4973b7638d10..5bd353af4ad3 100644 --- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -21,9 +21,12 @@ #include <string> #include <vector> +#include "android-base/stringprintf.h" #include "androidfw/ResourceTypes.h" #include "androidfw/StringPiece.h" +using android::base::StringPrintf; + using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask; using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; @@ -48,6 +51,29 @@ inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicySt {kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, {kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, }; + +inline static std::string PoliciesToDebugString(PolicyBitmask policies) { + std::string str; + uint32_t remaining = policies; + for (auto const& policy : kPolicyStringToFlag) { + if ((policies & policy.second) != policy.second) { + continue; + } + if (!str.empty()) { + str.append("|"); + } + str.append(policy.first.data()); + remaining &= ~policy.second; + } + if (remaining != 0) { + if (!str.empty()) { + str.append("|"); + } + str.append(StringPrintf("0x%08x", remaining)); + } + return !str.empty() ? str : "none"; +} + } // namespace android::idmap2::policy #endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_ diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp index db4778c8ee09..5fea7bcdaac5 100644 --- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp +++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp @@ -48,6 +48,11 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) { ASSERT_TRUE(result2); const auto idmap2 = std::move(*result2); + ASSERT_EQ(idmap1->GetHeader()->GetFulfilledPolicies(), + idmap2->GetHeader()->GetFulfilledPolicies()); + ASSERT_EQ(idmap1->GetHeader()->GetEnforceOverlayable(), + idmap2->GetHeader()->GetEnforceOverlayable()); + ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath()); ASSERT_EQ(idmap1->GetHeader()->GetTargetCrc(), idmap2->GetHeader()->GetTargetCrc()); ASSERT_EQ(idmap1->GetHeader()->GetTargetPath(), idmap2->GetHeader()->GetTargetPath()); ASSERT_EQ(idmap1->GetData().size(), 1U); diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 87da36c01192..6fab5e0f8ae1 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -62,9 +62,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) { std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream); ASSERT_THAT(header, NotNull()); ASSERT_EQ(header->GetMagic(), 0x504d4449U); - ASSERT_EQ(header->GetVersion(), 0x03U); + ASSERT_EQ(header->GetVersion(), 0x04U); ASSERT_EQ(header->GetTargetCrc(), 0x1234U); ASSERT_EQ(header->GetOverlayCrc(), 0x5678U); + ASSERT_EQ(header->GetFulfilledPolicies(), 0x11); + ASSERT_EQ(header->GetEnforceOverlayable(), true); ASSERT_EQ(header->GetTargetPath().to_string(), "targetX.apk"); ASSERT_EQ(header->GetOverlayPath().to_string(), "overlayX.apk"); ASSERT_EQ(header->GetDebugInfo(), "debug"); @@ -73,7 +75,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) { TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) { std::string raw(reinterpret_cast<const char*>(idmap_raw_data), idmap_raw_data_len); // overwrite the target path string, including the terminating null, with '.' - for (size_t i = 0x10; i < 0x110; i++) { + for (size_t i = 0x15; i < 0x115; i++) { raw[i] = '.'; } std::istringstream stream(raw); @@ -82,7 +84,7 @@ TEST(IdmapTests, FailToCreateIdmapHeaderFromBinaryStreamIfPathTooLong) { } TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) { - const size_t offset = 0x21c; + const size_t offset = 0x221; std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset), idmap_raw_data_len - offset); std::istringstream stream(raw); @@ -94,7 +96,7 @@ TEST(IdmapTests, CreateIdmapDataHeaderFromBinaryStream) { } TEST(IdmapTests, CreateIdmapDataFromBinaryStream) { - const size_t offset = 0x21c; + const size_t offset = 0x221; std::string raw(reinterpret_cast<const char*>(idmap_raw_data + offset), idmap_raw_data_len - offset); std::istringstream stream(raw); @@ -128,9 +130,11 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U); + ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), 0x11); + ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), "targetX.apk"); ASSERT_EQ(idmap->GetHeader()->GetOverlayPath().to_string(), "overlayX.apk"); @@ -180,9 +184,11 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x03U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x04U); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC); + ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC); + ASSERT_EQ(idmap->GetHeader()->GetEnforceOverlayable(), true); ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path); ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path); } @@ -389,7 +395,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream); ASSERT_THAT(header, NotNull()); - ASSERT_TRUE(header->IsUpToDate()); + ASSERT_TRUE(header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); // magic: bytes (0x0, 0x03) std::string bad_magic_string(stream.str()); @@ -402,7 +409,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_magic_stream); ASSERT_THAT(bad_magic_header, NotNull()); ASSERT_NE(header->GetMagic(), bad_magic_header->GetMagic()); - ASSERT_FALSE(bad_magic_header->IsUpToDate()); + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); // version: bytes (0x4, 0x07) std::string bad_version_string(stream.str()); @@ -415,7 +423,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_version_stream); ASSERT_THAT(bad_version_header, NotNull()); ASSERT_NE(header->GetVersion(), bad_version_header->GetVersion()); - ASSERT_FALSE(bad_version_header->IsUpToDate()); + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); // target crc: bytes (0x8, 0xb) std::string bad_target_crc_string(stream.str()); @@ -428,7 +437,8 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_target_crc_stream); ASSERT_THAT(bad_target_crc_header, NotNull()); ASSERT_NE(header->GetTargetCrc(), bad_target_crc_header->GetTargetCrc()); - ASSERT_FALSE(bad_target_crc_header->IsUpToDate()); + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); // overlay crc: bytes (0xc, 0xf) std::string bad_overlay_crc_string(stream.str()); @@ -441,27 +451,55 @@ TEST(IdmapTests, IdmapHeaderIsUpToDate) { IdmapHeader::FromBinaryStream(bad_overlay_crc_stream); ASSERT_THAT(bad_overlay_crc_header, NotNull()); ASSERT_NE(header->GetOverlayCrc(), bad_overlay_crc_header->GetOverlayCrc()); - ASSERT_FALSE(bad_overlay_crc_header->IsUpToDate()); - - // target path: bytes (0x10, 0x10f) + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); + + // fulfilled policy: bytes (0x10, 0x13) + std::string bad_policy_string(stream.str()); + bad_policy_string[0x10] = '.'; + bad_policy_string[0x11] = '.'; + bad_policy_string[0x12] = '.'; + bad_policy_string[0x13] = '.'; + std::stringstream bad_policy_stream(bad_policy_string); + std::unique_ptr<const IdmapHeader> bad_policy_header = + IdmapHeader::FromBinaryStream(bad_policy_stream); + ASSERT_THAT(bad_policy_header, NotNull()); + ASSERT_NE(header->GetFulfilledPolicies(), bad_policy_header->GetFulfilledPolicies()); + ASSERT_FALSE(bad_policy_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); + + // enforce overlayable: bytes (0x14) + std::string bad_enforce_string(stream.str()); + bad_enforce_string[0x14] = '\0'; + std::stringstream bad_enforce_stream(bad_enforce_string); + std::unique_ptr<const IdmapHeader> bad_enforce_header = + IdmapHeader::FromBinaryStream(bad_enforce_stream); + ASSERT_THAT(bad_enforce_header, NotNull()); + ASSERT_NE(header->GetEnforceOverlayable(), bad_enforce_header->GetEnforceOverlayable()); + ASSERT_FALSE(bad_enforce_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); + + // target path: bytes (0x15, 0x114) std::string bad_target_path_string(stream.str()); - bad_target_path_string[0x10] = '\0'; + bad_target_path_string[0x15] = '\0'; std::stringstream bad_target_path_stream(bad_target_path_string); std::unique_ptr<const IdmapHeader> bad_target_path_header = IdmapHeader::FromBinaryStream(bad_target_path_stream); ASSERT_THAT(bad_target_path_header, NotNull()); ASSERT_NE(header->GetTargetPath(), bad_target_path_header->GetTargetPath()); - ASSERT_FALSE(bad_target_path_header->IsUpToDate()); + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); - // overlay path: bytes (0x110, 0x20f) + // overlay path: bytes (0x115, 0x214) std::string bad_overlay_path_string(stream.str()); - bad_overlay_path_string[0x110] = '\0'; + bad_overlay_path_string[0x115] = '\0'; std::stringstream bad_overlay_path_stream(bad_overlay_path_string); std::unique_ptr<const IdmapHeader> bad_overlay_path_header = IdmapHeader::FromBinaryStream(bad_overlay_path_stream); ASSERT_THAT(bad_overlay_path_header, NotNull()); ASSERT_NE(header->GetOverlayPath(), bad_overlay_path_header->GetOverlayPath()); - ASSERT_FALSE(bad_overlay_path_header->IsUpToDate()); + ASSERT_FALSE(bad_magic_header->IsUpToDate(target_apk_path.c_str(), overlay_apk_path.c_str(), + PolicyFlags::PUBLIC, /* enforce_overlayable */ true)); } class TestVisitor : public Visitor { diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 5c5c81edee90..b268d5add141 100644 --- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp +++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp @@ -43,6 +43,8 @@ namespace android::idmap2 { << str << "--------"; \ } while (0) +#define ADDRESS "[0-9a-f]{8}: " + TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { fclose(stderr); // silence expected warnings @@ -62,15 +64,16 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { RawPrintVisitor visitor(stream); (*idmap)->accept(&visitor); -#define ADDRESS "[0-9a-f]{8}: " ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "00000003 version\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str()); ASSERT_CONTAINS_REGEX( StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING), stream.str()); ASSERT_CONTAINS_REGEX( StringPrintf(ADDRESS "%s overlay crc\n", android::idmap2::TestConstants::OVERLAY_CRC_STRING), stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000001 fulfilled policies: public\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count\n", stream.str()); @@ -83,7 +86,6 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) { ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 value: integer/int1\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1\n", stream.str()); ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1\n", stream.str()); -#undef ADDRESS } TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { @@ -99,22 +101,23 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { RawPrintVisitor visitor(stream); (*idmap)->accept(&visitor); - ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000004: 00000003 version\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000008: 00001234 target crc\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000000c: 00005678 overlay crc\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021c: 7f target package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021d: 7f overlay package id\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000021e: 00000003 target entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000222: 00000003 overlay entry count\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000226: 00000000 string pool index offset\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000022a: 00000000 string pool byte length\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000022e: 7f020000 target id\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000232: 01 type: reference\n"), std::string::npos); - ASSERT_NE(stream.str().find("00000233: 7f020000 value\n"), std::string::npos); - - ASSERT_NE(stream.str().find("00000249: 7f020000 overlay id\n"), std::string::npos); - ASSERT_NE(stream.str().find("0000024d: 7f020000 target id\n"), std::string::npos); + ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000004 version\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 01 enforce overlayable\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 7f target package id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 7f overlay package id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000003 target entry count\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool index offset\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool byte length\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS " 01 type: reference\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 value\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str()); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 5754eaf078a9..de039f440e33 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -287,26 +287,66 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsNoDefinedOverlayableAndNoTarget R::overlay::string::str4, false /* rewrite */)); } - -// Overlays that are pre-installed or are signed with the same signature as the target/actor can +// Overlays that are neither pre-installed nor signed with the same signature as the target cannot // overlay packages that have not defined overlayable resources. -TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { - constexpr PolicyBitmask kDefaultPolicies = - PolicyFlags::SIGNATURE | PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::PRODUCT_PARTITION | - PolicyFlags::SYSTEM_PARTITION | PolicyFlags::VENDOR_PARTITION | PolicyFlags::ODM_PARTITION | - PolicyFlags::OEM_PARTITION; +TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) { + auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", + "/overlay/overlay-no-name.apk", PolicyFlags::PUBLIC, + /* enforce_overlayable */ true); + + ASSERT_TRUE(resources) << resources.GetErrorMessage(); + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); +} - for (PolicyBitmask policy = 1U << (sizeof(PolicyBitmask) * 8 - 1); policy > 0; - policy = policy >> 1U) { +// Overlays that are pre-installed or are signed with the same signature as the target can overlay +// packages that have not defined overlayable resources. +TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { + auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void { auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", "/system-overlay-invalid/system-overlay-invalid.apk", - policy, /* enforce_overlayable */ true); - ASSERT_TRUE(resources) << resources.GetErrorMessage(); + fulfilled_policies, + /* enforce_overlayable */ true); - const size_t expected_overlaid = (policy & kDefaultPolicies) != 0 ? 10U : 0U; - ASSERT_EQ(expected_overlaid, resources->GetTargetToOverlayMap().size()) - << "Incorrect number of resources overlaid through policy " << policy; - } + ASSERT_TRUE(resources) << resources.GetErrorMessage(); + auto& res = *resources; + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); + ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::not_overlayable, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::other, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_actor, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_odm, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_oem, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_product, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_product, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_public, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_signature, + false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_system, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system, + false /* rewrite */)); + ASSERT_RESULT(MappingExists( + res, R::target::string::policy_system_vendor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_system_vendor, false /* rewrite */)); + }; + + CheckEntries(PolicyFlags::SIGNATURE); + CheckEntries(PolicyFlags::PRODUCT_PARTITION); + CheckEntries(PolicyFlags::SYSTEM_PARTITION); + CheckEntries(PolicyFlags::VENDOR_PARTITION); + CheckEntries(PolicyFlags::ODM_PARTITION); + CheckEntries(PolicyFlags::OEM_PARTITION); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index e899589c7e61..b599dcb0069a 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -30,7 +30,7 @@ const unsigned char idmap_raw_data[] = { 0x49, 0x44, 0x4d, 0x50, // 0x4: version - 0x03, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, // 0x8: target crc 0x34, 0x12, 0x00, 0x00, @@ -38,7 +38,13 @@ const unsigned char idmap_raw_data[] = { // 0xc: overlay crc 0x78, 0x56, 0x00, 0x00, - // 0x10: target path "targetX.apk" + // 0x10: fulfilled policies + 0x11, 0x00, 0x00, 0x00, + + // 0x14: enforce overlayable + 0x01, + + // 0x15: target path "targetX.apk" 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -56,7 +62,7 @@ const unsigned char idmap_raw_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x110: overlay path "overlayX.apk" + // 0x115: overlay path "overlayX.apk" 0x6f, 0x76, 0x65, 0x72, 0x6c, 0x61, 0x79, 0x58, 0x2e, 0x61, 0x70, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -74,7 +80,7 @@ const unsigned char idmap_raw_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - // 0x210: debug string + // 0x215: debug string // string length, including terminating null 0x08, 0x00, 0x00, 0x00, @@ -82,63 +88,63 @@ const unsigned char idmap_raw_data[] = { 0x64, 0x65, 0x62, 0x75, 0x67, 0x00, 0x00, 0x00, // DATA HEADER - // 0x21c: target_package_id + // 0x221: target_package_id 0x7f, - // 0x21d: overlay_package_id + // 0x222: overlay_package_id 0x7f, - // 0x21e: target_entry_count + // 0x223: target_entry_count 0x03, 0x00, 0x00, 0x00, - // 0x222: overlay_entry_count + // 0x227: overlay_entry_count 0x03, 0x00, 0x00, 0x00, - // 0x226: string_pool_offset + // 0x22b: string_pool_offset 0x00, 0x00, 0x00, 0x00, - // 0x22a: string_pool_byte_length + // 0x22f: string_pool_byte_length 0x00, 0x00, 0x00, 0x00, // TARGET ENTRIES - // 0x22e: 0x7f020000 + // 0x233: 0x7f020000 0x00, 0x00, 0x02, 0x7f, - // 0x232: TYPE_REFERENCE + // 0x237: TYPE_REFERENCE 0x01, - // 0x233: 0x7f020000 + // 0x238: 0x7f020000 0x00, 0x00, 0x02, 0x7f, - // 0x237: 0x7f030000 + // 0x23c: 0x7f030000 0x00, 0x00, 0x03, 0x7f, - // 0x23b: TYPE_REFERENCE + // 0x240: TYPE_REFERENCE 0x01, - // 0x23c: 0x7f030000 + // 0x241: 0x7f030000 0x00, 0x00, 0x03, 0x7f, - // 0x240: 0x7f030002 + // 0x245: 0x7f030002 0x02, 0x00, 0x03, 0x7f, - // 0x244: TYPE_REFERENCE + // 0x249: TYPE_REFERENCE 0x01, - // 0x245: 0x7f030001 + // 0x24a: 0x7f030001 0x01, 0x00, 0x03, 0x7f, // OVERLAY ENTRIES - // 0x249: 0x7f020000 -> 0x7f020000 + // 0x24e: 0x7f020000 -> 0x7f020000 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f, - // 0x251: 0x7f030000 -> 0x7f030000 + // 0x256: 0x7f030000 -> 0x7f030000 0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f, - // 0x259: 0x7f030001 -> 0x7f030002 + // 0x25e: 0x7f030001 -> 0x7f030002 0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f}; -const unsigned int idmap_raw_data_len = 0x261; +const unsigned int idmap_raw_data_len = 0x266; std::string GetTestDataPath(); diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp index 61e5eb07130c..33e764988b75 100644 --- a/cmds/incidentd/src/Section.cpp +++ b/cmds/incidentd/src/Section.cpp @@ -477,14 +477,15 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const { // Run dumping thread const uint64_t start = Nanotime(); - std::thread worker([&]() { + std::thread worker([write_fd = std::move(dumpPipe.writeFd()), service = std::move(service), + this]() mutable { // Don't crash the service if writing to a closed pipe (may happen if dumping times out) signal(SIGPIPE, sigpipe_handler); - status_t err = service->dump(dumpPipe.writeFd().get(), mArgs); + status_t err = service->dump(write_fd.get(), this->mArgs); if (err != OK) { ALOGW("[%s] dump thread failed. Error: %s", this->name.string(), strerror(-err)); } - dumpPipe.writeFd().reset(); + write_fd.reset(); }); // Collect dump content diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 095dd1e9be59..e7b32c56551a 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -529,7 +529,9 @@ void StatsLogProcessor::OnConfigUpdatedLocked( VLOG("StatsdConfig valid"); } else { // If there is any error in the config, don't use it. + // Remove any existing config with the same key. ALOGE("StatsdConfig NOT valid"); + mMetricsManagers.erase(key); } } diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 7090bd46635d..23f2584655b0 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -284,6 +284,7 @@ private: FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize); FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast); FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge); + FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved); FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead); FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot); FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBootMultipleActivations); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 47bab2947aaf..6f952f637506 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -267,8 +267,11 @@ void StatsService::dumpIncidentSection(int out) { for (const ConfigKey& configKey : mConfigManager->GetAllConfigKeys()) { uint64_t reportsListToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_REPORTS_LIST); + // Don't include the current bucket to avoid skipping buckets. + // If we need to include the current bucket later, consider changing to NO_TIME_CONSTRAINTS + // or other alternatives to avoid skipping buckets for pulled metrics. mProcessor->onDumpReport(configKey, getElapsedRealtimeNs(), - true /* includeCurrentBucket */, false /* erase_data */, + false /* includeCurrentBucket */, false /* erase_data */, ADB_DUMP, FAST, &proto); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 36a8b2cfc084..dc20a02156cb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -43,6 +43,7 @@ import "frameworks/base/core/proto/android/server/location/enums.proto"; import "frameworks/base/core/proto/android/service/procstats_enum.proto"; import "frameworks/base/core/proto/android/service/usb.proto"; import "frameworks/base/core/proto/android/stats/connectivity/network_stack.proto"; +import "frameworks/base/core/proto/android/stats/connectivity/tethering.proto"; import "frameworks/base/core/proto/android/stats/dnsresolver/dns_resolver.proto"; import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto"; import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto"; @@ -193,7 +194,7 @@ message Atom { BiometricAcquired biometric_acquired = 87 [(module) = "framework"]; BiometricAuthenticated biometric_authenticated = 88 [(module) = "framework"]; BiometricErrorOccurred biometric_error_occurred = 89 [(module) = "framework"]; - UiEventReported ui_event_reported = 90 [(module) = "framework"]; + UiEventReported ui_event_reported = 90 [(module) = "framework", (module) = "sysui"]; BatteryHealthSnapshot battery_health_snapshot = 91; SlowIo slow_io = 92; BatteryCausedShutdown battery_caused_shutdown = 93; @@ -419,7 +420,7 @@ message Atom { DisplayJankReported display_jank_reported = 257; AppStandbyBucketChanged app_standby_bucket_changed = 258 [(module) = "framework"]; SharesheetStarted sharesheet_started = 259 [(module) = "framework"]; - RankingSelected ranking_selected = 260 [(module) = "framework"]; + RankingSelected ranking_selected = 260 [(module) = "framework", (module) = "sysui"]; TvSettingsUIInteracted tvsettings_ui_interacted = 261 [(module) = "tv_settings"]; LauncherStaticLayout launcher_snapshot = 262 [(module) = "sysui"]; PackageInstallerV2Reported package_installer_v2_reported = 263 [(module) = "framework"]; @@ -444,6 +445,47 @@ message Atom { TvTunerStateChanged tv_tuner_state_changed = 276 [(module) = "framework"]; MediaOutputOpSwitchReported mediaoutput_op_switch_reported = 277 [(module) = "settings"]; + CellBroadcastMessageFiltered cb_message_filtered = + 278 [(module) = "cellbroadcast"]; + TvTunerDvrStatus tv_tuner_dvr_status = 279 [(module) = "framework"]; + TvCasSessionOpenStatus tv_cas_session_open_status = + 280 [(module) = "framework"]; + AssistantInvocationReported assistant_invocation_reported = 281 [(module) = "framework"]; + DisplayWakeReported display_wake_reported = 282 [(module) = "framework"]; + CarUserHalModifyUserRequestReported car_user_hal_modify_user_request_reported = + 283 [(module) = "car"]; + CarUserHalModifyUserResponseReported car_user_hal_modify_user_response_reported = + 284 [(module) = "car"]; + CarUserHalPostSwitchResponseReported car_user_hal_post_switch_response_reported = + 285 [(module) = "car"]; + CarUserHalInitialUserInfoRequestReported car_user_hal_initial_user_info_request_reported = + 286 [(module) = "car"]; + CarUserHalInitialUserInfoResponseReported car_user_hal_initial_user_info_response_reported = + 287 [(module) = "car"]; + CarUserHalUserAssociationRequestReported car_user_hal_user_association_request_reported = + 288 [(module) = "car"]; + CarUserHalSetUserAssociationResponseReported car_user_hal_set_user_association_response_reported = + 289 [(module) = "car"]; + NetworkIpProvisioningReported network_ip_provisioning_reported = + 290 [(module) = "network_stack"]; + NetworkDhcpRenewReported network_dhcp_renew_reported = 291 [(module) = "network_stack"]; + NetworkValidationReported network_validation_reported = 292 [(module) = "network_stack"]; + NetworkStackQuirkReported network_stack_quirk_reported = 293 [(module) = "network_stack"]; + MediametricsAudioRecordDeviceUsageReported mediametrics_audiorecorddeviceusage_reported = + 294; + MediametricsAudioThreadDeviceUsageReported mediametrics_audiothreaddeviceusage_reported = + 295; + MediametricsAudioTrackDeviceUsageReported mediametrics_audiotrackdeviceusage_reported = + 296; + MediametricsAudioDeviceConnectionReported mediametrics_audiodeviceconnection_reported = + 297; + BlobCommitted blob_committed = 298 [(module) = "framework"]; + BlobLeased blob_leased = 299 [(module) = "framework"]; + BlobOpened blob_opened = 300 [(module) = "framework"]; + ContactsProviderStatusReported contacts_provider_status_reported = 301; + KeystoreKeyEventReported keystore_key_event_reported = 302; + NetworkTetheringReported network_tethering_reported = + 303 [(module) = "network_tethering"]; // StatsdStats tracks platform atoms with ids upto 500. // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value. @@ -541,10 +583,11 @@ message Atom { SimSlotState sim_slot_state = 10078 [(module) = "telephony"]; SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"]; SettingSnapshot setting_snapshot = 10080 [(module) = "framework"]; - DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"]; + BlobInfo blob_info = 10081 [(module) = "framework"]; DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"]; BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered = 10083 [(module) = "framework"]; + DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"]; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -4870,6 +4913,94 @@ message SnapshotMergeReported { optional int64 cow_file_size_bytes = 5; } +/** + * Event representing when BlobStoreManager.Session#commit() is called + * + * Logged from: + * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java + */ +message BlobCommitted { + // Uid of the Blob committer + optional int32 uid = 1 [(is_uid) = true]; + + // Id of the Blob committed + optional int64 blob_id = 2; + + // Size of the Blob + optional int64 size = 3; + + enum Result { + UNKNOWN = 0; + // Commit Succeeded + SUCCESS = 1; + // Commit Failed: Error occurred during commit + ERROR_DURING_COMMIT = 2; + // Commit Failed: Digest of the data did not match Blob digest + DIGEST_MISMATCH = 3; + } + optional Result result = 4; +} + +/** + * Event representing when BlobStoreManager#acquireLease() is called + * + * Logged from: + * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java + */ +message BlobLeased{ + // Uid of the Blob leasee + optional int32 uid = 1 [(is_uid) = true]; + + // Id of the Blob leased or 0 if the Blob does not exist + optional int64 blob_id = 2; + + // Size of the Blob or 0 if the Blob does not exist + optional int64 size = 3; + + enum Result { + UNKNOWN = 0; + // Lease Succeeded + SUCCESS = 1; + // Lease Failed: Blob does not exist + BLOB_DNE = 2; + // Lease Failed: Leasee does not have access to the Blob + ACCESS_NOT_ALLOWED = 3; + // Lease Failed: Leasee requested an invalid expiry duration + LEASE_EXPIRY_INVALID = 4; + // Lease Failed: Leasee has exceeded the total data lease limit + DATA_SIZE_LIMIT_EXCEEDED = 5; + } + optional Result result = 4; +} + +/** + * Event representing when BlobStoreManager#openBlob() is called + * + * Logged from: + * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java + */ +message BlobOpened{ + // Uid of the Blob opener + optional int32 uid = 1 [(is_uid) = true]; + + // Id of the Blob opened or 0 if the Blob does not exist + optional int64 blob_id = 2; + + // Size of the Blob or 0 if the Blob does not exist + optional int64 size = 3; + + enum Result { + UNKNOWN = 0; + // Open Succeeded + SUCCESS = 1; + // Open Failed: Blob does not exist + BLOB_DNE = 2; + // Open Failed: Opener does not have access to the Blob + ACCESS_NOT_ALLOWED = 3; + } + optional Result result = 4; +} + ////////////////////////////////////////////////////////////////////// // Pulled atoms below this line // ////////////////////////////////////////////////////////////////////// @@ -5798,7 +5929,7 @@ message ProcessStatsProto { optional string process = 1; // Uid of the process. - optional int32 uid = 2; + optional int32 uid = 2 [(is_uid) = true]; // Information about how often kills occurred message Kill { @@ -5825,13 +5956,16 @@ message ProcessStatsProto { repeated ProcessStatsAssociationProto assocs = 7; } -// Next Tag: 5 +// Next Tag: 6 message ProcessStatsAssociationProto { // Procss Name of the associated process (client process of service binding) optional string assoc_process_name = 1; // Package Name of the associated package (client package of service binding) - optional string assoc_package_name = 2; + optional string assoc_package_name = 2 [deprecated = true]; + + // UID of the associated process/package (client package of service binding) + optional int32 assoc_uid = 5 [(is_uid) = true]; // Total count of the times this association (service binding) appeared. optional int32 total_count = 3; @@ -6059,6 +6193,76 @@ message PackageNotificationChannelPreferences { } /** + * Atom that represents an item in the list of Do Not Disturb rules, pulled from + * NotificationManagerService.java. + */ +message DNDModeProto { + enum Mode { + ROOT_CONFIG = -1; // Used to distinguish the config (one per user) from the rules. + ZEN_MODE_OFF = 0; + ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; + ZEN_MODE_NO_INTERRUPTIONS = 2; + ZEN_MODE_ALARMS = 3; + } + optional int32 user = 1; // Android user ID (0, 1, 10, ...) + optional bool enabled = 2; // true for ROOT_CONFIG if a manualRule is enabled + optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG + optional Mode zen_mode = 4; + // id is one of the system default rule IDs, or empty + // May also be "MANUAL_RULE" to indicate app-activation of the manual rule. + optional string id = 5; + optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other + optional DNDPolicyProto policy = 7; +} + +/** + * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto. + */ +message DNDPolicyProto { + enum State { + STATE_UNSET = 0; + STATE_ALLOW = 1; + STATE_DISALLOW = 2; + } + optional State calls = 1; + optional State repeat_callers = 2; + optional State messages = 3; + optional State conversations = 4; + optional State reminders = 5; + optional State events = 6; + optional State alarms = 7; + optional State media = 8; + optional State system = 9; + optional State fullscreen = 10; + optional State lights = 11; + optional State peek = 12; + optional State status_bar = 13; + optional State badge = 14; + optional State ambient = 15; + optional State notification_list = 16; + + enum PeopleType { + PEOPLE_UNSET = 0; + PEOPLE_ANYONE = 1; + PEOPLE_CONTACTS = 2; + PEOPLE_STARRED = 3; + PEOPLE_NONE = 4; + } + + optional PeopleType allow_calls_from = 17; + optional PeopleType allow_messages_from = 18; + + enum ConversationType { + CONV_UNSET = 0; + CONV_ANYONE = 1; + CONV_IMPORTANT = 2; + CONV_NONE = 3; + } + + optional ConversationType allow_conversations_from = 19; +} + +/** * Atom that contains a list of a package's channel group preferences, pulled from * NotificationManagerService.java. */ @@ -6309,6 +6513,16 @@ message ContentCaptureServiceEvents { SET_WHITELIST = 3; SET_DISABLED = 4; ON_USER_DATA_REMOVED = 5; + ON_DATA_SHARE_REQUEST = 6; + ACCEPT_DATA_SHARE_REQUEST = 7; + REJECT_DATA_SHARE_REQUEST = 8; + DATA_SHARE_WRITE_FINISHED = 9; + DATA_SHARE_ERROR_IOEXCEPTION = 10; + DATA_SHARE_ERROR_EMPTY_DATA = 11; + DATA_SHARE_ERROR_CLIENT_PIPE_FAIL = 12; + DATA_SHARE_ERROR_SERVICE_PIPE_FAIL = 13; + DATA_SHARE_ERROR_CONCURRENT_REQUEST = 14; + DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 15; } optional Event event = 1; // component/package of content capture service. @@ -6680,6 +6894,24 @@ message AppCompacted { } /** + * Logs when a Tethering event occurs. + * + */ +message NetworkTetheringReported { + // tethering error code + optional android.stats.connectivity.ErrorCode error_code = 1; + + // tethering downstream type + optional android.stats.connectivity.DownstreamType downstream_type = 2; + + // transport type of upstream network + optional android.stats.connectivity.UpstreamType upstream_type = 3; + + // The user type of Tethering + optional android.stats.connectivity.UserType user_type= 4; +} + +/** * Logs a DNS lookup operation initiated by the system resolver on behalf of an application * invoking native APIs such as getaddrinfo() or Java APIs such as Network#getAllByName(). * @@ -6717,6 +6949,172 @@ message NetworkDnsEventReported { } /** + * logs the CapportApiData info + * Logged from: + * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java + */ +message CapportApiData { + // The TTL of the network connection provided by captive portal + optional int32 remaining_ttl_secs = 1; + + // The limit traffic data of the network connection provided by captive portal + optional int32 remaining_bytes = 2; + + // Is portal url option included in the DHCP packet (Yes, No) + optional bool has_portal_url = 3; + + // Is venue info (e.g. store info, maps, flight status) included (Yes, No) + optional bool has_venue_info = 4; +} + +/** + * logs a network Probe Event + * Logged from: + * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java + */ +message ProbeEvent { + // The probe type (http or https, or captive portal API...) + optional android.stats.connectivity.ProbeType probe_type = 1; + + // The latency in microseconds of the probe event + optional int32 latency_micros = 2; + + // The result of the probe event + optional android.stats.connectivity.ProbeResult probe_result = 3; + + // The CaptivePortal API info + optional CapportApiData capport_api_data = 4; +} + +/** + * log each ProbeEvent in ProbeEvents + * Logged from: + * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java + */ +message ProbeEvents { + // Record probe event during the validation + repeated ProbeEvent probe_event = 1; +} + +/** + * The DHCP (Dynamic Host Configuration Protocol) session info + * Logged from: + * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java + */ +message DhcpSession { + // The DHCP Feature(s) enabled in this session + repeated android.stats.connectivity.DhcpFeature used_features = 1; + + // The discover packet (re)transmit count + optional int32 discover_count = 2; + + // The request packet (re)transmit count + optional int32 request_count = 3; + + // The IPv4 address conflict count + // (only be meaningful when duplicate address detection is enabled) + optional int32 conflict_count = 4; + + // The DHCP packet parsing error code in this session + // (defined in android.net.metrics.DhcpErrorEvent) + repeated android.stats.connectivity.DhcpErrorCode error_code = 5; + + // The result of DHCP hostname transliteration + optional android.stats.connectivity.HostnameTransResult ht_result = 6; +} + +/** + * Logs Network IP provisioning event + * Logged from: + * packages/modules/NetworkStack/src/com/android/networkstack/metrics/NetworkIpProvisioningMetrics.java + */ +message NetworkIpProvisioningReported { + // Transport type (WIFI, CELLULAR, BLUETOOTH, ..) + optional android.stats.connectivity.TransportType transport_type = 1; + + // The latency in microseconds of IP Provisioning over IPV4 + optional int32 ipv4_latency_micros = 2; + + // The latency in microseconds of IP Provisioning over IPV6 + optional int32 ipv6_latency_micros = 3; + + // The time duration between provisioning start and end (success or failure) + optional int64 provisioning_duration_micros = 4; + + // The specific disconnect reason for this IP provisioning + optional android.stats.connectivity.DisconnectCode disconnect_code = 5; + + // Log DHCP session info (Only valid for IPv4) + optional DhcpSession dhcp_session = 6 [(log_mode) = MODE_BYTES]; + + // The random number between 0 ~ 999 for sampling + optional int32 random_number = 7; +} + +/** + * Logs Network DHCP Renew event + * Logged from: + * packages/modules/NetworkStack/src/android/net/dhcp/DhcpClient.java + */ +message NetworkDhcpRenewReported { + // Transport type (WIFI, CELLULAR, BLUETOOTH, ..) + optional android.stats.connectivity.TransportType transport_type = 1; + + // The request packet (re)transmit count + optional int32 request_count = 2; + + // The latency in microseconds of DHCP Renew + optional int32 latency_micros = 3; + + // The DHCP error code is defined in android.net.metrics.DhcpErrorEvent + optional android.stats.connectivity.DhcpErrorCode error_code = 4; + + // The result of DHCP renew + optional android.stats.connectivity.DhcpRenewResult renew_result = 5; + + // The random number between 0 ~ 999 for sampling + optional int32 random_number = 6; +} + +/** + * Logs Network Validation event + * Logged from: + * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java + */ +message NetworkValidationReported { + // Transport type (WIFI, CELLULAR, BLUETOOTH, ..) + optional android.stats.connectivity.TransportType transport_type = 1; + + // Record each probe event + optional ProbeEvents probe_events = 2 [(log_mode) = MODE_BYTES]; + + // The result of the network validation + optional android.stats.connectivity.ValidationResult validation_result = 3; + + // The latency in microseconds of network validation + optional int32 latency_micros = 4; + + // The validation index (the first validation attempt or second, third...) + optional int32 validation_index = 5; + + // The random number between 0 ~ 999 for sampling + optional int32 random_number = 6; +} + +/** + * Logs NetworkStack Quirk event + * Logged from: + * packages/modules/NetworkStack/src/com/android/networkstack/ + */ +message NetworkStackQuirkReported { + // Transport type (WIFI, CELLULAR, BLUETOOTH, ..) + optional android.stats.connectivity.TransportType transport_type = 1; + + // Record each Quirk event + optional android.stats.connectivity.NetworkQuirkEvent event = 2; +} + +/** * Logs when a data stall event occurs. * * Log from: @@ -7992,6 +8390,245 @@ message CarPowerStateChanged { } /** + * Logs when Car User Hal is requested to switch/create/remove user. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalModifyUserRequestReported { + // Request id for the request. + optional int32 request_id = 1; + // Request type. + enum RequestType { + UNKNOWN = 0; + // Car user manager requested user switch. + SWITCH_REQUEST_ANDROID = 1; + // OEM requested User switch. + SWITCH_REQUEST_OEM = 2; + // Hal switch requested after android switch using activity manager. + SWITCH_REQUEST_LEGACY = 3; + // Create User + CREATE_REQUEST = 4; + // Remove User + REMOVE_REQUEST = 5; + } + optional RequestType request_type = 2; + // Android User id of the current user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 user_id = 3; + // VHAL flags of the current user. (-1 if not available) + optional int32 user_flags = 4; + // Android User id of the target user for switch/create/remove. It can only + // be 0, 10, 11 and so on. -1 if not available. + optional int32 target_user_id = 5; + // VHAL flags of the target user for switch/create/remove. (-1 if not available) + optional int32 target_user_flags = 6; + // Request timeout Milliseconds (-1 if not available) + optional int32 timeout_millis = 7; +} + +/** + * Logs when Car User Hal responds to switch/create user request. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalModifyUserResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + + // Hal request status for user switch/create/remove. + enum HalRequestStatus { + UNSPECIFIED = 0; + // Hal request for user switch/create is successful. + SUCCESS = 1; + // Hal request for user switch/create failed. + FAILURE = 2; + } + optional HalRequestStatus request_status = 3; +} + +/** + * Logs when post switch response is posted to Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalPostSwitchResponseReported { + // Request id. + optional int32 request_id = 1; + + // Android user switch status. + enum UserSwitchStatus { + UNKNOWN = 0; + // Android user switch is successful. + SUCCESS = 1; + // Android user switch failed. + FAILURE = 2; + } + optional UserSwitchStatus switch_status = 2; +} + +/** + * Logs when initial user information is requested from Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalInitialUserInfoRequestReported { + // Request id for the request. + optional int32 request_id = 1; + + // Request type for initial user information. + enum InitialUserInfoRequestType { + UNKNOWN = 0; + // At the first time Android was booted (or after a factory reset). + FIRST_BOOT = 1; + // At the first time Android was booted after the system was updated. + FIRST_BOOT_AFTER_OTA = 2; + // When Android was booted "from scratch". + COLD_BOOT = 3; + // When Android was resumed after the system was suspended to memory. + RESUME = 4; + } + optional InitialUserInfoRequestType request_type = 2; + // Request timeout Milliseconds (-1 if not available) + optional int32 timeout_millis = 3; +} + +/** + * Logs when Car User Hal responds to initial user information requests. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalInitialUserInfoResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + // Response for initial user information request. + enum InitialUserInfoResponseAction { + UNSPECIFIED = 0; + // Let the Android System decide what to do. + DEFAULT = 1; + // Switch to an existing Android user. + SWITCH = 2; + // Create a new Android user (and switch to it). + CREATE = 3; + } + optional InitialUserInfoResponseAction response_action = 3; + // Android User id of the target user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 target_user = 4; + // VHAL flags of the current user. (-1 if not available) + optional int32 target_user_flags = 5; + // User locales + optional string user_locales = 6; +} + +/** + * Logs when set user association is requested from Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalUserAssociationRequestReported { + // Request id for the request. + optional int32 request_id = 1; + // Request type. + enum RequestType { + UNKNOWN = 0; + // For setting user association information. + SET = 1; + // For getting user association information. + GET = 2; + } + optional RequestType request_type = 2; + // Android User id of the current user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 current_user_id = 3; + // VHAL flags of the current user. (-1 if not available) + optional int32 current_user_flags = 4; + // Number of the set associations requested. + optional int32 number_associations = 5; + // Concatenated string for the types from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_types = 6; + // Concatenated string for the values from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_values = 7; +} + +/** + * Logs when Car User Hal responds to set user association requests. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalSetUserAssociationResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + // Number of the set associations in the response. + optional int32 number_associations = 3; + // Concatenated string for the types from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_types = 4; + // Concatenated string for the values from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_values = 5; +} + +/** * Logs whether GarageMode is entered. * * Logged from: @@ -9134,8 +9771,10 @@ message IntegrityRulesPushed { /** * Logs when a cell broadcast message is received on the device. * - * Logged from CellBroadcastService module: + * Logged from Cell Broadcast module and platform: * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + * packages/apps/CellBroadcastReceiver/ + * frameworks/opt/telephony/src/java/com/android/internal/telephony/CellBroadcastServiceManager.java */ message CellBroadcastMessageReported { // The type of Cell Broadcast message @@ -9146,8 +9785,40 @@ message CellBroadcastMessageReported { CDMA_SPC = 3; } + // The parts of the cell broadcast message pipeline + enum ReportSource { + UNKNOWN_SOURCE = 0; + FRAMEWORK = 1; + CB_SERVICE = 2; + CB_RECEIVER_APP = 3; + } + // GSM, CDMA, CDMA-SCP optional CbType type = 1; + + // The source of the report + optional ReportSource source = 2; +} + +/** + * Logs when a cell broadcast message is filtered out, or otherwise intentionally not sent to CBR. + * + * Logged from CellBroadcastService module: + * packages/modules/CellBroadcastService/src/com/android/cellbroadcastservice/ + */ +message CellBroadcastMessageFiltered { + enum FilterReason { + NOT_FILTERED = 0; + DUPLICATE_MESSAGE = 1; + GEOFENCED_MESSAGE = 2; + AREA_INFO_MESSAGE = 3; + } + + // GSM, CDMA, CDMA-SCP + optional CellBroadcastMessageReported.CbType type = 1; + + // The source of the report + optional FilterReason filter = 2; } /** @@ -9174,6 +9845,7 @@ message CellBroadcastMessageError { UNEXPECTED_GSM_MESSAGE_TYPE_FROM_FWK = 12; UNEXPECTED_CDMA_MESSAGE_TYPE_FROM_FWK = 13; UNEXPECTED_CDMA_SCP_MESSAGE_TYPE_FROM_FWK = 14; + NO_CONNECTION_TO_CB_SERVICE = 15; } // What kind of error occurred @@ -9205,6 +9877,100 @@ message TvTunerStateChanged { // new state optional State state = 2; } + +/** + * Logs the status of a dvr playback or record. + * This is atom ID 279. + * + * Logged from: + * frameworks/base/media/java/android/media/tv/tuner/dvr + */ +message TvTunerDvrStatus { + enum Type { + UNKNOWN_TYPE = 0; + PLAYBACK = 1; // is a playback + RECORD = 2; // is a record + } + enum State { + UNKNOWN_STATE = 0; + STARTED = 1; // DVR is started + STOPPED = 2; // DVR is stopped + } + // The uid of the application that sent this custom atom. + optional int32 uid = 1 [(is_uid) = true]; + // DVR type + optional Type type = 2; + // DVR state + optional State state = 3; + // Identify the segment of a record or playback + optional int32 segment_id = 4; + // indicate how many overflow or underflow happened between started to stopped + optional int32 overflow_underflow_count = 5; +} + +/** + * Logs when a cas session opened through MediaCas. + * This is atom ID 280. + * + * Logged from: + * frameworks/base/media/java/android/media/MediaCas.java + */ +message TvCasSessionOpenStatus { + enum State { + UNKNOWN = 0; + SUCCEEDED = 1; // indicate that the session is opened successfully. + FAILED = 2; // indicate that the session isn’t opened successfully. + } + // The uid of the application that sent this custom atom. + optional int32 uid = 1 [(is_uid) = true]; + // Cas system Id + optional int32 cas_system_id = 2; + // State of the session + optional State state = 3; +} + +/** + * Logs for ContactsProvider general usage. + * This is atom ID 301. + * + * Logged from: + * packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java + */ +message ContactsProviderStatusReported { + enum ApiType { + UNKNOWN_API = 0; + QUERY = 1; + // INSERT includes insert and bulkInsert, and inserts triggered by applyBatch. + INSERT = 2; + // UPDATE and DELETE includes update/delete and the ones triggered by applyBatch. + UPDATE = 3; + DELETE = 4; + } + + enum ResultType { + UNKNOWN_RESULT = 0; + SUCCESS = 1; + FAIL = 2; + ILLEGAL_ARGUMENT = 3; + UNSUPPORTED_OPERATION = 4; + } + + enum CallerType { + UNSPECIFIED_CALLER_TYPE = 0; + CALLER_IS_SYNC_ADAPTER = 1; + CALLER_IS_NOT_SYNC_ADAPTER = 2; + } + + optional ApiType api_type = 1; + // Defined in + // packages/providers/ContactsProvider/src/com/android/providers/contacts/ContactsProvider2.java + optional int32 uri_type = 2; + optional CallerType caller_type = 3; + optional ResultType result_type = 4; + optional int32 result_count = 5; + optional int64 latency_micros = 6; +} + /** * Logs when an app is frozen or unfrozen. * @@ -9398,7 +10164,7 @@ message GnssStats { optional int64 time_to_first_fix_reports = 3; // Total pulled reported time to first fix (in milli-seconds) since boot - optional int64 time_to_first_fix_milli_s = 4; + optional int64 time_to_first_fix_millis = 4; // Number of position accuracy reports since boot optional int64 position_accuracy_reports = 5; @@ -9721,15 +10487,20 @@ message AccessibilityServiceReported { optional android.stats.accessibility.ServiceStatus service_status = 2; } -message DisplayWakeReason { +/** + * Logs when display wake up. + * + * Logged from: + * services/core/java/com/android/server/power/Notifier.java + */ + +message DisplayWakeReported { // Wake_up_reason code // If LOWORD(wake_up_reason) = 0 // reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX // else reference wake_up_reason to - // frameworks/base/services/core/java/com/android/server/power/Notifier.java#DispWakeupReason + // services/core/java/com/android/server/power/Notifier.java#onWakeUp optional int32 wake_up_reason = 1; - // Count of wake up by reason - optional int32 wake_times = 2; } /** @@ -9903,3 +10674,453 @@ message MediaOutputOpSwitchReported { // The amount of applied devices within a remote dynamic group after a switching is done. optional int32 applied_device_count_within_remote_group = 9; } + +/** + * Logs when the Assistant is invoked. + * + * Logged from: + * frameworks/base/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java + */ +message AssistantInvocationReported { + + // The event_id (as for UiEventReported). + optional int32 event_id = 1; + + // The registered Assistant's uid and package (as for UiEventReported). + optional int32 uid = 2 [(is_uid) = true]; + optional string package_name = 3; + + // An identifier used to disambiguate which logs refer to a particular invocation of the + // Assistant (as for UiEventReported). + optional int32 instance_id = 4; + + // The state of the device at the time of invocation. + enum DeviceState { + UNKNOWN_DEVICE_STATE = 0; + AOD1 = 1; + AOD2 = 2; + BOUNCER = 3; + UNLOCKED_LOCKSCREEN = 4; + LAUNCHER_HOME = 5; + LAUNCHER_OVERVIEW = 6; + LAUNCHER_ALL_APPS = 7; + APP_DEFAULT = 8; + APP_IMMERSIVE = 9; + APP_FULLSCREEN = 10; + } + optional DeviceState device_state = 5; + + // Whether the Assistant handles were showing at the time of invocation. + optional bool assistant_handles_showing = 6; +} + +/** + * Logs when an AudioRecord finishes running on an audio device + * + * Logged from: + * frameworks/av/services/mediametrics/AudioAnalytics.cpp + */ +message MediametricsAudioRecordDeviceUsageReported { + // The devices connected to this AudioRecord. + // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2". + // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp + // See audio_device_t in system/media/audio/include/system/audio-base.h + optional string devices = 1; + + // The name of the remote device attached to the device, typically available for USB or BT. + // This may be empty for a fixed device, or separated by "|" if more than one. + optional string device_names = 2; + + // The amount of time spent in the device as measured by the active track in AudioFlinger. + optional int64 device_time_nanos = 3; + + // The audio data format used for encoding. + // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t + optional string encoding = 4; + + // The client-server buffer framecount. + // The framecount is generally between 960 - 48000 for PCM encoding. + // The framecount represents raw buffer size in bytes for non-PCM encoding. + optional int32 frame_count = 5; + + // The number of audio intervals (contiguous, continuous playbacks). + optional int32 interval_count = 6; + + // The sample rate of the AudioRecord. + // A number generally between 8000-96000 (frames per second). + optional int32 sample_rate = 7; + + // The audio input flags used to construct the AudioRecord. + // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t + optional string flags = 8; + + // The santized package name of the audio client associated with the AudioRecord. + // See getSanitizedPackageNameAndVersionCode() in + // frameworks/av/services/mediametrics/MediaMetricsService.cpp + optional string package_name = 9; + + // The selected device id (nonzero if a non-default device is selected) + optional int32 selected_device_id = 10; + + // The caller of the AudioRecord. + // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp + optional string caller = 11; + + // The audio source for AudioRecord. + // An enumeration from system/media/audio/include/system/audio-base.h audio_source_t + optional string source = 12; +} + +/** + * Logs when an AudioThread finishes running on an audio device + * + * Logged from: + * frameworks/av/services/mediametrics/AudioAnalytics.cpp + */ +message MediametricsAudioThreadDeviceUsageReported { + // The devices connected to this audio thread. + // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2". + // (for record threads): + // See lookup<INPUT_DEVICE> in frameworks/av/services/mediametrics/AudioTypes.cpp + // (for playback threads): + // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp + // See audio_device_t in system/media/audio/include/system/audio-base.h + optional string devices = 1; + + // The name of the remote device attached to the device, typically available for USB or BT. + // This may be empty for a fixed device, or separated by "|" if more than one. + optional string device_names = 2; + + // The amount of time spent in the device as measured by the active track in AudioFlinger. + optional int64 device_time_nanos = 3; + + // The audio data format used for encoding. + // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t + optional string encoding = 4; + + // The framecount of the buffer delivered to (or from) the HAL. + // The framecount is generally ~960 for PCM encoding. + // The framecount represents raw buffer size in bytes for non-PCM encoding. + optional int32 frame_count = 5; + + // The number of audio intervals (contiguous, continuous playbacks). + optional int32 interval_count = 6; + + // The sample rate of the audio thread. + // A number generally between 8000-96000 (frames per second). + optional int32 sample_rate = 7; + + // The audio flags used to construct the thread + // (for record threads): + // A string OR from system/media/audio/include/system/audio-base.h audio_input_flags_t + // (for playback threads): + // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t + optional string flags = 8; + + // The number of underruns encountered for a playback thread or the + // number of overruns encountered for a capture thread. + optional int32 xruns = 9; + + // The type of thread + // A thread type enumeration from + // frameworks/av/mediametrics/services/Translate.h + optional string type = 10; +} + +/** + * Logs when an AudioTrack finishes running on an audio device + * + * Logged from: + * frameworks/av/services/mediametrics/AudioAnalytics.cpp + */ +message MediametricsAudioTrackDeviceUsageReported { + // The output devices connected to this AudioTrack. + // A string OR of various output device categories, e.g. "DEVICE1|DEVICE2". + // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp + // See audio_device_t in system/media/audio/include/system/audio-base.h + optional string devices = 1; + + // The name of the remote device attached to the device, typically available for USB or BT. + // This may be empty for a fixed device, or separated by "|" if more than one. + optional string device_names = 2; + + // The amount of time spent in the device as measured by the active track in AudioFlinger. + optional int64 device_time_nanos = 3; + + // The audio data format used for encoding. + // An enumeration from system/media/audio/include/system/audio-base.h audio_format_t + optional string encoding = 4; + + // The client-server buffer framecount. + // The framecount is generally between 960 - 48000 for PCM encoding. + // The framecount represents raw buffer size in bytes for non-PCM encoding. + // A static track (see traits) may have a very large framecount. + optional int32 frame_count = 5; + + // The number of audio intervals (contiguous, continuous playbacks). + optional int32 interval_count = 6; + + // The sample rate of the AudioTrack. + // A number generally between 8000-96000 (frames per second). + optional int32 sample_rate = 7; + + // The audio flags used to construct the AudioTrack. + // A string OR from system/media/audio/include/system/audio-base.h audio_output_flags_t + optional string flags = 8; + + // The number of underruns encountered. + optional int32 xruns = 9; + + // The santized package name of the audio client associated with the AudioTrack. + // See getSanitizedPackageNameAndVersionCode() in + // frameworks/av/services/mediametrics/MediaMetricsService.cpp + optional string package_name = 10; + + // The latency of the last sample in the buffer in milliseconds. + optional float device_latency_millis = 11; + + // The startup time in milliseconds from start() to sample played. + optional float device_startup_millis = 12; + + // The average volume of the track on the device [ 0.f - 1.f ] + optional float device_volume = 13; + + // The selected device id (nonzero if a non-default device is selected) + optional int32 selected_device_id = 14; + + // The stream_type category for the AudioTrack. + // An enumeration from system/media/audio/include/system/audio-base.h audio_stream_type_t + optional string stream_type = 15; + + // The usage for the AudioTrack. + // An enumeration from system/media/audio/include/system/audio-base.h audio_usage_t + optional string usage = 16; + + // The content type of the AudioTrack. + // An enumeration from system/media/audio/include/system/audio-base.h audio_content_type_t + optional string content_type = 17; + + // The caller of the AudioTrack. + // See lookup<CALLER_NAME>() in frameworks/av/services/mediametrics/AudioTypes.cpp + optional string caller = 18; + + // The traits of the AudioTrack. + // A string OR of different traits, may be empty string. + // Only "static" is supported for R. + // See lookup<TRACK_TRAITS>() in frameworks/av/services/mediametrics/AudioTypes.cpp + optional string traits = 19; +} + +/** + * Logs the status of an audio device connection attempt. + * + * Logged from: + * frameworks/av/services/mediametrics/AudioAnalytics.cpp + */ +message MediametricsAudioDeviceConnectionReported { + // The input devices represented by this report. + // A string OR of various input device categories, e.g. "DEVICE1|DEVICE2". + // See lookup<INPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp + // See audio_device_t in system/media/audio/include/system/audio-base.h + optional string input_devices = 1; + + // The output devices represented by this report. + // A string OR of various output device categories. + // See lookup<OUTPUT_DEVICE>() in frameworks/av/services/mediametrics/AudioTypes.cpp + // See audio_device_t in system/media/audio/include/system/audio-base.h + optional string output_devices = 2; + + // The name of the remote device attached to the device, typically available for USB or BT. + // This may be empty for a fixed device, or separated by "|" if more than one. + optional string device_names = 3; + + // The result of the audio device connection. + // 0 indicates success: connection verified. + // 1 indicates unknown: connection not verified or not known if diverted properly. + // Other values indicate specific status. + // See DeviceConnectionResult in frameworks/av/services/mediametrics/AudioTypes.h + optional int32 result = 4; + + // Average milliseconds of time to connect + optional float time_to_connect_millis = 5; + + // Number of connections if aggregated statistics, otherwise 1. + optional int32 connection_count = 6; +} + +/** + * Logs: i) creation of different types of cryptographic keys in the keystore, + * ii) operations performed using the keys, + * iii) attestation of the keys + * Logged from: system/security/keystore/key_event_log_handler.cpp + */ +message KeystoreKeyEventReported { + + enum Algorithm { + /** Asymmetric algorithms. */ + RSA = 1; + // 2 removed, do not reuse. + EC = 3; + /** Block cipher algorithms */ + AES = 32; + TRIPLE_DES = 33; + /** MAC algorithms */ + HMAC = 128; + }; + /** Algorithm associated with the key */ + optional Algorithm algorithm = 1; + + /** Size of the key */ + optional int32 key_size = 2; + + enum KeyOrigin { + /** Generated in keymaster. Should not exist outside the TEE. */ + GENERATED = 0; + /** Derived inside keymaster. Likely exists off-device. */ + DERIVED = 1; + /** Imported into keymaster. Existed as cleartext in Android. */ + IMPORTED = 2; + /** Keymaster did not record origin. */ + UNKNOWN = 3; + /** Securely imported into Keymaster. */ + SECURELY_IMPORTED = 4; + }; + /* Logs whether the key was generated, imported, securely imported, or derived.*/ + optional KeyOrigin key_origin = 3; + + enum HardwareAuthenticatorType { + NONE = 0; + PASSWORD = 1; + FINGERPRINT = 2; + // Additional entries must be powers of 2. + }; + /** + * What auth types does this key require? If none, + * then no auth required. + */ + optional HardwareAuthenticatorType user_auth_type = 4; + + /** + * If user authentication is required, is the requirement time based? If it + * is not time based then this field will not be used and the key is per + * operation. Per operation keys must be user authenticated on each usage. + */ + optional int32 user_auth_key_timeout_secs = 5; + + /** + * padding mode, digest, block_mode and purpose should ideally be repeated + * fields. However, since statsd does not support repeated fields in + * pushed atoms, they are represented using bitmaps. + */ + + /** Track which padding mode is being used.*/ + optional int32 padding_mode_bitmap = 6; + + /** Track which digest is being used. */ + optional int32 digest_bitmap = 7; + + /** Track what block mode is being used (for encryption). */ + optional int32 block_mode_bitmap = 8; + + /** Track what purpose is this key serving. */ + optional int32 purpose_bitmap = 9; + + enum EcCurve { + P_224 = 0; + P_256 = 1; + P_384 = 2; + P_521 = 3; + }; + /** Which ec curve was selected if elliptic curve cryptography is in use **/ + optional EcCurve ec_curve = 10; + + enum KeyBlobUsageRequirements { + STANDALONE = 0; + REQUIRES_FILE_SYSTEM = 1; + }; + /** Standalone or is a file system required */ + optional KeyBlobUsageRequirements key_blob_usage_reqs = 11; + + enum Type { + key_operation = 0; + key_creation = 1; + key_attestation = 2; + } + /** Key creation event, operation event or attestation event? */ + optional Type type = 12; + + /** Was the key creation, operation, or attestation successful? */ + optional bool was_successful = 13; + + /** Response code or error code */ + optional int32 error_code = 14; +} + +// Blob Committer stats +// Keep in sync between: +// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto +// frameworks/base/cmds/statsd/src/atoms.proto +message BlobCommitterProto { + // Committer app's uid + optional int32 uid = 1 [(is_uid) = true]; + + // Unix epoch timestamp of the commit in milliseconds + optional int64 commit_timestamp_millis = 2; + + // Flags of what access types the committer has set for the Blob + optional int32 access_mode = 3; + + // Number of packages that have been whitelisted for ACCESS_TYPE_WHITELIST + optional int32 num_whitelisted_package = 4; +} + +// Blob Leasee stats +// Keep in sync between: +// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto +// frameworks/base/cmds/statsd/src/atoms.proto +message BlobLeaseeProto { + // Leasee app's uid + optional int32 uid = 1 [(is_uid) = true]; + + // Unix epoch timestamp for lease expiration in milliseconds + optional int64 lease_expiry_timestamp_millis = 2; +} + +// List of Blob Committers +// Keep in sync between: +// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto +// frameworks/base/cmds/statsd/src/atoms.proto +message BlobCommitterListProto { + repeated BlobCommitterProto committer = 1; +} + +// List of Blob Leasees +// Keep in sync between: +// frameworks/base/core/proto/android/server/blobstoremanagerservice.proto +// frameworks/base/cmds/statsd/src/atoms.proto +message BlobLeaseeListProto { + repeated BlobLeaseeProto leasee = 1; +} + +/** + * Logs the current state of a Blob committed with BlobStoreManager + * + * Pulled from: + * frameworks/base/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java + */ +message BlobInfo { + // Id of the Blob + optional int64 blob_id = 1; + + // Size of the Blob data + optional int64 size = 2; + + // Unix epoch timestamp of the Blob's expiration in milliseconds + optional int64 expiry_timestamp_millis = 3; + + // List of committers of this Blob + optional BlobCommitterListProto committers = 4; + + // List of leasees of this Blob + optional BlobLeaseeListProto leasees = 5; +} diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 8e8912ae7d44..005048446fc3 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -101,7 +101,7 @@ public: // Per atom dimension key size limit static const std::map<int, std::pair<size_t, size_t>> kAtomDimensionKeySizeLimitMap; - const static int kMaxConfigCountPerUid = 10; + const static int kMaxConfigCountPerUid = 20; const static int kMaxAlertCountPerConfig = 100; const static int kMaxConditionCountPerConfig = 300; const static int kMaxMetricCountPerConfig = 1000; @@ -669,6 +669,8 @@ private: FRIEND_TEST(StatsdStatsTest, TestAtomMetricsStats); FRIEND_TEST(StatsdStatsTest, TestActivationBroadcastGuardrailHit); FRIEND_TEST(StatsdStatsTest, TestAtomErrorStats); + + FRIEND_TEST(StatsLogProcessorTest, InvalidConfigRemoved); }; } // namespace statsd diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index cdd20cdd70f9..fe143e496373 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -98,7 +98,7 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo // Stores atom id to primary key pairs for each state atom that the metric is // sliced by. - std::map<int, HashableDimensionKey> statePrimaryKeys; + std::map<int32_t, HashableDimensionKey> statePrimaryKeys; // For states with primary fields, use MetricStateLinks to get the primary // field values from the log event. These values will form a primary key diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index e8c575a1adea..7e825efddb75 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -361,8 +361,12 @@ void MetricsManager::onDumpReport(const int64_t dumpTimeStampNs, protoOutput->end(token); } - mLastReportTimeNs = dumpTimeStampNs; - mLastReportWallClockNs = getWallClockNs(); + // Do not update the timestamps when data is not cleared to avoid timestamps from being + // misaligned. + if (erase_data) { + mLastReportTimeNs = dumpTimeStampNs; + mLastReportWallClockNs = getWallClockNs(); + } VLOG("=========================Metric Reports End=========================="); } diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index c0d117402314..5987a723a421 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -189,11 +189,6 @@ void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId, VLOG("ValueMetric %lld onStateChanged time %lld, State %d, key %s, %d -> %d", (long long)mMetricId, (long long)eventTimeNs, atomId, primaryKey.toString().c_str(), oldState.mValue.int_value, newState.mValue.int_value); - // If condition is not true or metric is not active, we do not need to pull - // for this state change. - if (mCondition != ConditionState::kTrue || !mIsActive) { - return; - } // If old and new states are in the same StateGroup, then we do not need to // pull for this state change. @@ -205,6 +200,12 @@ void ValueMetricProducer::onStateChanged(int64_t eventTimeNs, int32_t atomId, return; } + // If condition is not true or metric is not active, we do not need to pull + // for this state change. + if (mCondition != ConditionState::kTrue || !mIsActive) { + return; + } + bool isEventLate = eventTimeNs < mCurrentBucketStartTimeNs; if (isEventLate) { VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs, @@ -412,7 +413,6 @@ void ValueMetricProducer::resetBase() { for (auto& slice : mCurrentBaseInfo) { for (auto& baseInfo : slice.second) { baseInfo.hasBase = false; - baseInfo.hasCurrentState = false; } } mHasGlobalBase = false; @@ -625,7 +625,6 @@ void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<Log auto it = mCurrentBaseInfo.find(whatKey); for (auto& baseInfo : it->second) { baseInfo.hasBase = false; - baseInfo.hasCurrentState = false; } } } @@ -820,6 +819,8 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( Interval& interval = intervals[i]; interval.valueIndex = i; Value value; + baseInfo.hasCurrentState = true; + baseInfo.currentState = stateKey; if (!getDoubleOrLong(event, matcher, value)) { VLOG("Failed to get value %d from event %s", i, event.ToString().c_str()); StatsdStats::getInstance().noteBadValueType(mMetricId); @@ -907,7 +908,6 @@ void ValueMetricProducer::onMatchedLogEventInternalLocked( interval.hasValue = true; } interval.sampleSize += 1; - baseInfo.currentState = stateKey; } // Only trigger the tracker if all intervals are correct @@ -951,6 +951,7 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, const int64_t& nextBucketStartTimeNs) { if (mCondition == ConditionState::kUnknown) { StatsdStats::getInstance().noteBucketUnknownCondition(mMetricId); + invalidateCurrentBucketWithoutResetBase(eventTimeNs, BucketDropReason::CONDITION_UNKNOWN); } VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs, @@ -959,7 +960,10 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs(); int64_t bucketEndTime = fullBucketEndTimeNs; int64_t numBucketsForward = calcBucketsForwardCount(eventTimeNs); - if (numBucketsForward > 1) { + + // Skip buckets if this is a pulled metric or a pushed metric that is diffed. + if (numBucketsForward > 1 && (mIsPulled || mUseDiff)) { + VLOG("Skipping forward %lld buckets", (long long)numBucketsForward); StatsdStats::getInstance().noteSkippedForwardBuckets(mMetricId); // Something went wrong. Maybe the device was sleeping for a long time. It is better diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 3de5b99a2b09..b359af745c91 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -75,7 +75,7 @@ public: if (!mSplitBucketForAppUpgrade) { return; } - if (mIsPulled && mCondition) { + if (mIsPulled && mCondition == ConditionState::kTrue) { pullAndMatchEventsLocked(eventTimeNs); } flushCurrentBucketLocked(eventTimeNs, eventTimeNs); @@ -84,7 +84,7 @@ public: // ValueMetric needs special logic if it's a pulled atom. void onStatsdInitCompleted(const int64_t& eventTimeNs) override { std::lock_guard<std::mutex> lock(mMutex); - if (mIsPulled && mCondition) { + if (mIsPulled && mCondition == ConditionState::kTrue) { pullAndMatchEventsLocked(eventTimeNs); } flushCurrentBucketLocked(eventTimeNs, eventTimeNs); @@ -313,6 +313,7 @@ private: FRIEND_TEST(ValueMetricProducerTest, TestSlicedState); FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithMap); FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions); + FRIEND_TEST(ValueMetricProducerTest, TestSlicedStateWithCondition); FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey); FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase); FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures); diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index 72decf2c7bd0..acdffd3d4712 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -198,6 +198,9 @@ message EventMetric { optional int64 condition = 3; repeated MetricConditionLink links = 4; + + reserved 100; + reserved 101; } message CountMetric { @@ -218,6 +221,9 @@ message CountMetric { repeated MetricStateLink state_link = 9; optional FieldMatcher dimensions_in_condition = 7 [deprecated = true]; + + reserved 100; + reserved 101; } message DurationMetric { @@ -245,6 +251,9 @@ message DurationMetric { optional TimeUnit bucket = 7; optional FieldMatcher dimensions_in_condition = 8 [deprecated = true]; + + reserved 100; + reserved 101; } message GaugeMetric { @@ -281,6 +290,9 @@ message GaugeMetric { optional int32 max_pull_delay_sec = 13 [default = 30]; optional bool split_bucket_for_app_upgrade = 14 [default = true]; + + reserved 100; + reserved 101; } message ValueMetric { @@ -333,6 +345,9 @@ message ValueMetric { optional bool split_bucket_for_app_upgrade = 17 [default = true]; optional FieldMatcher dimensions_in_condition = 9 [deprecated = true]; + + reserved 100; + reserved 101; } message Alert { diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp index 23f8ca4e74e6..a21eb9b9147f 100644 --- a/cmds/statsd/tests/FieldValue_test.cpp +++ b/cmds/statsd/tests/FieldValue_test.cpp @@ -33,6 +33,12 @@ namespace android { namespace os { namespace statsd { +// These constants must be kept in sync with those in StatsDimensionsValue.java. +const static int STATS_DIMENSIONS_VALUE_STRING_TYPE = 2; +const static int STATS_DIMENSIONS_VALUE_INT_TYPE = 3; +const static int STATS_DIMENSIONS_VALUE_FLOAT_TYPE = 6; +const static int STATS_DIMENSIONS_VALUE_TUPLE_TYPE = 7; + namespace { void makeLogEvent(LogEvent* logEvent, const int32_t atomId, const int64_t timestamp, const vector<int>& attributionUids, const vector<string>& attributionTags, @@ -291,34 +297,76 @@ TEST(AtomMatcherTest, TestWriteDimensionPath) { } } -//TODO(b/149050405) Update this test for StatsDimensionValueParcel -//TEST(AtomMatcherTest, TestSubscriberDimensionWrite) { -// HashableDimensionKey dim; -// -// int pos1[] = {1, 1, 1}; -// int pos2[] = {1, 1, 2}; -// int pos3[] = {1, 1, 3}; -// int pos4[] = {2, 0, 0}; -// -// Field field1(10, pos1, 2); -// Field field2(10, pos2, 2); -// Field field3(10, pos3, 2); -// Field field4(10, pos4, 0); -// -// Value value1((int32_t)10025); -// Value value2("tag"); -// Value value3((int32_t)987654); -// Value value4((int32_t)99999); -// -// dim.addValue(FieldValue(field1, value1)); -// dim.addValue(FieldValue(field2, value2)); -// dim.addValue(FieldValue(field3, value3)); -// dim.addValue(FieldValue(field4, value4)); -// -// SubscriberReporter::getStatsDimensionsValue(dim); -// // TODO(b/110562792): can't test anything here because StatsDimensionsValue class doesn't -// // have any read api. -//} +void checkAttributionNodeInDimensionsValueParcel(StatsDimensionsValueParcel& attributionNodeParcel, + int32_t nodeDepthInAttributionChain, + int32_t uid, string tag) { + EXPECT_EQ(attributionNodeParcel.field, nodeDepthInAttributionChain /*position at depth 1*/); + ASSERT_EQ(attributionNodeParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE); + ASSERT_EQ(attributionNodeParcel.tupleValue.size(), 2); + + StatsDimensionsValueParcel uidParcel = attributionNodeParcel.tupleValue[0]; + EXPECT_EQ(uidParcel.field, 1 /*position at depth 2*/); + EXPECT_EQ(uidParcel.valueType, STATS_DIMENSIONS_VALUE_INT_TYPE); + EXPECT_EQ(uidParcel.intValue, uid); + + StatsDimensionsValueParcel tagParcel = attributionNodeParcel.tupleValue[1]; + EXPECT_EQ(tagParcel.field, 2 /*position at depth 2*/); + EXPECT_EQ(tagParcel.valueType, STATS_DIMENSIONS_VALUE_STRING_TYPE); + EXPECT_EQ(tagParcel.stringValue, tag); +} + +// Test conversion of a HashableDimensionKey into a StatsDimensionValueParcel +TEST(AtomMatcherTest, TestSubscriberDimensionWrite) { + int atomId = 10; + // First four fields form an attribution chain + int pos1[] = {1, 1, 1}; + int pos2[] = {1, 1, 2}; + int pos3[] = {1, 2, 1}; + int pos4[] = {1, 2, 2}; + int pos5[] = {2, 1, 1}; + + Field field1(atomId, pos1, /*depth=*/2); + Field field2(atomId, pos2, /*depth=*/2); + Field field3(atomId, pos3, /*depth=*/2); + Field field4(atomId, pos4, /*depth=*/2); + Field field5(atomId, pos5, /*depth=*/0); + + Value value1((int32_t)1); + Value value2("string2"); + Value value3((int32_t)3); + Value value4("string4"); + Value value5((float)5.0); + + HashableDimensionKey dimensionKey; + dimensionKey.addValue(FieldValue(field1, value1)); + dimensionKey.addValue(FieldValue(field2, value2)); + dimensionKey.addValue(FieldValue(field3, value3)); + dimensionKey.addValue(FieldValue(field4, value4)); + dimensionKey.addValue(FieldValue(field5, value5)); + + StatsDimensionsValueParcel rootParcel = dimensionKey.toStatsDimensionsValueParcel(); + EXPECT_EQ(rootParcel.field, atomId); + ASSERT_EQ(rootParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE); + ASSERT_EQ(rootParcel.tupleValue.size(), 2); + + // Check that attribution chain is populated correctly + StatsDimensionsValueParcel attributionChainParcel = rootParcel.tupleValue[0]; + EXPECT_EQ(attributionChainParcel.field, 1 /*position at depth 0*/); + ASSERT_EQ(attributionChainParcel.valueType, STATS_DIMENSIONS_VALUE_TUPLE_TYPE); + ASSERT_EQ(attributionChainParcel.tupleValue.size(), 2); + checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[0], + /*nodeDepthInAttributionChain=*/1, + value1.int_value, value2.str_value); + checkAttributionNodeInDimensionsValueParcel(attributionChainParcel.tupleValue[1], + /*nodeDepthInAttributionChain=*/2, + value3.int_value, value4.str_value); + + // Check that the float is populated correctly + StatsDimensionsValueParcel floatParcel = rootParcel.tupleValue[1]; + EXPECT_EQ(floatParcel.field, 2 /*position at depth 0*/); + EXPECT_EQ(floatParcel.valueType, STATS_DIMENSIONS_VALUE_FLOAT_TYPE); + EXPECT_EQ(floatParcel.floatValue, value5.float_value); +} TEST(AtomMatcherTest, TestWriteDimensionToProto) { HashableDimensionKey dim; diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 076f32752223..1e6680c47567 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -13,6 +13,11 @@ // limitations under the License. #include "StatsLogProcessor.h" + +#include <gmock/gmock.h> +#include <gtest/gtest.h> +#include <stdio.h> + #include "StatsService.h" #include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/stats_log.pb.h" @@ -20,16 +25,10 @@ #include "guardrail/StatsdStats.h" #include "logd/LogEvent.h" #include "packages/UidMap.h" -#include "storage/StorageManager.h" #include "statslog_statsdtest.h" - -#include <gmock/gmock.h> -#include <gtest/gtest.h> - +#include "storage/StorageManager.h" #include "tests/statsd_test_util.h" -#include <stdio.h> - using namespace android; using namespace testing; using ::ndk::SharedRefBase; @@ -324,6 +323,41 @@ TEST(StatsLogProcessorTest, TestPullUidProviderSetOnConfigUpdate) { EXPECT_EQ(pullerManager->mPullUidProviders.find(key), pullerManager->mPullUidProviders.end()); } +TEST(StatsLogProcessorTest, InvalidConfigRemoved) { + // Setup simple config key corresponding to empty config. + StatsdStats::getInstance().reset(); + sp<UidMap> m = new UidMap(); + sp<StatsPullerManager> pullerManager = new StatsPullerManager(); + m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, + {String16("p1"), String16("p2")}, {String16(""), String16("")}); + sp<AlarmMonitor> anomalyAlarmMonitor; + sp<AlarmMonitor> subscriberAlarmMonitor; + StatsLogProcessor p(m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [](const ConfigKey& key) { return true; }, + [](const int&, const vector<int64_t>&) {return true;}); + ConfigKey key(3, 4); + StatsdConfig config = MakeConfig(true); + p.OnConfigUpdated(0, key, config); + EXPECT_EQ(1, p.mMetricsManagers.size()); + EXPECT_NE(p.mMetricsManagers.find(key), p.mMetricsManagers.end()); + // Cannot assert the size of mConfigStats since it is static and does not get cleared on reset. + EXPECT_NE(StatsdStats::getInstance().mConfigStats.end(), + StatsdStats::getInstance().mConfigStats.find(key)); + EXPECT_EQ(0, StatsdStats::getInstance().mIceBox.size()); + + StatsdConfig invalidConfig = MakeConfig(true); + invalidConfig.clear_allowed_log_source(); + p.OnConfigUpdated(0, key, invalidConfig); + EXPECT_EQ(0, p.mMetricsManagers.size()); + // The current configs should not contain the invalid config. + EXPECT_EQ(StatsdStats::getInstance().mConfigStats.end(), + StatsdStats::getInstance().mConfigStats.find(key)); + // Both "config" and "invalidConfig" should be in the icebox. + EXPECT_EQ(2, StatsdStats::getInstance().mIceBox.size()); + +} + + TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) { int uid = 1111; @@ -1796,6 +1830,53 @@ TEST(StatsLogProcessorTest_mapIsolatedUidToHostUid, LogIsolatedUidAttributionCha EXPECT_EQ(field2, actualFieldValues->at(5).mValue.int_value); } +TEST(StatsLogProcessorTest, TestDumpReportWithoutErasingDataDoesNotUpdateTimestamp) { + int hostUid = 20; + int isolatedUid = 30; + sp<MockUidMap> mockUidMap = makeMockUidMapForOneHost(hostUid, {isolatedUid}); + ConfigKey key(3, 4); + + // TODO: All tests should not persist state on disk. This removes any reports that were present. + ProtoOutputStream proto; + StorageManager::appendConfigMetricsReport(key, &proto, /*erase data=*/true, /*isAdb=*/false); + + StatsdConfig config = MakeConfig(false); + sp<StatsLogProcessor> processor = + CreateStatsLogProcessor(1, 1, config, key, nullptr, 0, mockUidMap); + vector<uint8_t> bytes; + + int64_t dumpTime1Ns = 1 * NS_PER_SEC; + processor->onDumpReport(key, dumpTime1Ns, false /* include_current_bucket */, + true /* erase_data */, ADB_DUMP, FAST, &bytes); + + ConfigMetricsReportList output; + output.ParseFromArray(bytes.data(), bytes.size()); + EXPECT_EQ(output.reports_size(), 1); + EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime1Ns); + + int64_t dumpTime2Ns = 5 * NS_PER_SEC; + processor->onDumpReport(key, dumpTime2Ns, false /* include_current_bucket */, + false /* erase_data */, ADB_DUMP, FAST, &bytes); + + // Check that the dump report without clearing data is successful. + output.ParseFromArray(bytes.data(), bytes.size()); + EXPECT_EQ(output.reports_size(), 1); + EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime2Ns); + EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns); + + int64_t dumpTime3Ns = 10 * NS_PER_SEC; + processor->onDumpReport(key, dumpTime3Ns, false /* include_current_bucket */, + true /* erase_data */, ADB_DUMP, FAST, &bytes); + + // Check that the previous dump report that didn't clear data did not overwrite the first dump's + // timestamps. + output.ParseFromArray(bytes.data(), bytes.size()); + EXPECT_EQ(output.reports_size(), 1); + EXPECT_EQ(output.reports(0).current_report_elapsed_nanos(), dumpTime3Ns); + EXPECT_EQ(output.reports(0).last_report_elapsed_nanos(), dumpTime1Ns); + +} + #else GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 1bcc35d99d18..5666501d7d51 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -167,6 +167,32 @@ public: return valueProducer; } + static sp<ValueMetricProducer> createValueProducerWithConditionAndState( + sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric, + vector<int32_t> slicedStateAtoms, + unordered_map<int, unordered_map<int, int64_t>> stateGroupMap, + ConditionState conditionAfterFirstBucketPrepared) { + UidMap uidMap; + SimpleAtomMatcher atomMatcher; + atomMatcher.set_atom_id(tagId); + sp<EventMatcherWizard> eventMatcherWizard = + new EventMatcherWizard({new SimpleLogMatchingTracker( + atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)}); + sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>(); + EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, kConfigKey, _, _, _)) + .WillOnce(Return()); + EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, kConfigKey, _)) + .WillRepeatedly(Return()); + + sp<ValueMetricProducer> valueProducer = new ValueMetricProducer( + kConfigKey, metric, 0 /* condition tracker index */, {ConditionState::kUnknown}, + wizard, logEventMatcherIndex, eventMatcherWizard, tagId, bucketStartTimeNs, + bucketStartTimeNs, pullerManager, {}, {}, slicedStateAtoms, stateGroupMap); + valueProducer->prepareFirstBucket(); + valueProducer->mCondition = conditionAfterFirstBucketPrepared; + return valueProducer; + } + static ValueMetric createMetric() { ValueMetric metric; metric.set_id(metricId); @@ -188,6 +214,13 @@ public: metric.add_slice_by_state(StringToId(state)); return metric; } + + static ValueMetric createMetricWithConditionAndState(string state) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); + metric.set_condition(StringToId("SCREEN_ON")); + metric.add_slice_by_state(StringToId(state)); + return metric; + } }; // Setup for parameterized tests. @@ -3262,11 +3295,15 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenConditionEventWron report.value_metrics().skipped(0).start_bucket_elapsed_millis()); EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100), report.value_metrics().skipped(0).end_bucket_elapsed_millis()); - ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); + ASSERT_EQ(2, report.value_metrics().skipped(0).drop_event_size()); auto dropEvent = report.value_metrics().skipped(0).drop_event(0); EXPECT_EQ(BucketDropReason::EVENT_IN_WRONG_BUCKET, dropEvent.drop_reason()); EXPECT_EQ(NanoToMillis(bucket2StartTimeNs - 100), dropEvent.drop_time_millis()); + + dropEvent = report.value_metrics().skipped(0).drop_event(1); + EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs + 100), dropEvent.drop_time_millis()); } /* @@ -3582,7 +3619,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) { sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerWithCondition( - pullerManager, metric, ConditionState::kUnknown); + pullerManager, metric, ConditionState::kFalse); // Check dump report. ProtoOutputStream output; @@ -3608,6 +3645,94 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) { } /* + * Test that all buckets are dropped due to condition unknown until the first onConditionChanged. + */ +TEST(ValueMetricProducerTest_BucketDrop, TestConditionUnknownMultipleBuckets) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + // Condition change to true. + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data, bool) { + EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC); + data->clear(); + data->push_back(CreateRepeatedValueLogEvent( + tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 10)); + return true; + })) + // Dump report requested. + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data, bool) { + EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 15 * NS_PER_SEC); + data->clear(); + data->push_back(CreateRepeatedValueLogEvent( + tagId, bucket2StartTimeNs + 15 * NS_PER_SEC, 15)); + return true; + })); + + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition( + pullerManager, metric, ConditionState::kUnknown); + + // Bucket should be dropped because of condition unknown. + int64_t appUpgradeTimeNs = bucketStartTimeNs + 5 * NS_PER_SEC; + valueProducer->notifyAppUpgrade(appUpgradeTimeNs); + + // Bucket also dropped due to condition unknown + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs + 1, 3)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + // This bucket is also dropped due to condition unknown. + int64_t conditionChangeTimeNs = bucket2StartTimeNs + 10 * NS_PER_SEC; + valueProducer->onConditionChanged(true, conditionChangeTimeNs); + + // Check dump report. + ProtoOutputStream output; + std::set<string> strSet; + int64_t dumpReportTimeNs = bucket2StartTimeNs + 15 * NS_PER_SEC; // 15 seconds + valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true, + NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_value_metrics()); + ASSERT_EQ(0, report.value_metrics().data_size()); + ASSERT_EQ(3, report.value_metrics().skipped_size()); + + EXPECT_EQ(NanoToMillis(bucketStartTimeNs), + report.value_metrics().skipped(0).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), + report.value_metrics().skipped(0).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); + + auto dropEvent = report.value_metrics().skipped(0).drop_event(0); + EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), dropEvent.drop_time_millis()); + + EXPECT_EQ(NanoToMillis(appUpgradeTimeNs), + report.value_metrics().skipped(1).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), + report.value_metrics().skipped(1).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size()); + + dropEvent = report.value_metrics().skipped(1).drop_event(0); + EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), dropEvent.drop_time_millis()); + + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), + report.value_metrics().skipped(2).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(dumpReportTimeNs), + report.value_metrics().skipped(2).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(2).drop_event_size()); + + dropEvent = report.value_metrics().skipped(2).drop_event(0); + EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(conditionChangeTimeNs), dropEvent.drop_time_millis()); +} + +/* * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket * was not flushed in time. */ @@ -3893,13 +4018,13 @@ TEST(ValueMetricProducerTest, TestSlicedState) { return true; })); + StateManager::getInstance().clear(); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerWithState( pullerManager, metric, {util::SCREEN_STATE_CHANGED}, {}); EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size()); // Set up StateManager and check that StateTrackers are initialized. - StateManager::getInstance().clear(); StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer); EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); @@ -4105,12 +4230,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { } } + StateManager::getInstance().clear(); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerWithState( pullerManager, metric, {util::SCREEN_STATE_CHANGED}, stateGroupMap); // Set up StateManager and check that StateTrackers are initialized. - StateManager::getInstance().clear(); StateManager::getInstance().registerListener(SCREEN_STATE_ATOM_ID, valueProducer); EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); EXPECT_EQ(1, StateManager::getInstance().getListenersCount(SCREEN_STATE_ATOM_ID)); @@ -4357,12 +4482,12 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { return true; })); + StateManager::getInstance().clear(); sp<ValueMetricProducer> valueProducer = ValueMetricProducerTestHelper::createValueProducerWithState( pullerManager, metric, {UID_PROCESS_STATE_ATOM_ID}, {}); // Set up StateManager and check that StateTrackers are initialized. - StateManager::getInstance().clear(); StateManager::getInstance().registerListener(UID_PROCESS_STATE_ATOM_ID, valueProducer); EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); EXPECT_EQ(1, StateManager::getInstance().getListenersCount(UID_PROCESS_STATE_ATOM_ID)); @@ -4722,6 +4847,212 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithPrimaryField_WithDimensions) { EXPECT_EQ(5, report.value_metrics().data(4).bucket_info(1).values(0).value_long()); } +TEST(ValueMetricProducerTest, TestSlicedStateWithCondition) { + // Set up ValueMetricProducer. + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithConditionAndState( + "BATTERY_SAVER_MODE_STATE"); + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + EXPECT_CALL(*pullerManager, Pull(tagId, kConfigKey, _, _, _)) + // Condition changed to true. + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data, bool) { + EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 20 * NS_PER_SEC); + data->clear(); + data->push_back( + CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 20 * NS_PER_SEC, 3)); + return true; + })) + // Battery saver mode state changed to OFF. + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data, bool) { + EXPECT_EQ(eventTimeNs, bucketStartTimeNs + 30 * NS_PER_SEC); + data->clear(); + data->push_back( + CreateRepeatedValueLogEvent(tagId, bucketStartTimeNs + 30 * NS_PER_SEC, 5)); + return true; + })) + // Condition changed to false. + .WillOnce(Invoke([](int tagId, const ConfigKey&, const int64_t eventTimeNs, + vector<std::shared_ptr<LogEvent>>* data, bool) { + EXPECT_EQ(eventTimeNs, bucket2StartTimeNs + 10 * NS_PER_SEC); + data->clear(); + data->push_back(CreateRepeatedValueLogEvent( + tagId, bucket2StartTimeNs + 10 * NS_PER_SEC, 15)); + return true; + })); + + StateManager::getInstance().clear(); + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithConditionAndState( + pullerManager, metric, {util::BATTERY_SAVER_MODE_STATE_CHANGED}, {}, + ConditionState::kFalse); + EXPECT_EQ(1, valueProducer->mSlicedStateAtoms.size()); + + // Set up StateManager and check that StateTrackers are initialized. + StateManager::getInstance().registerListener(util::BATTERY_SAVER_MODE_STATE_CHANGED, + valueProducer); + EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount()); + EXPECT_EQ(1, StateManager::getInstance().getListenersCount( + util::BATTERY_SAVER_MODE_STATE_CHANGED)); + + // Bucket status after battery saver mode ON event. + // Condition is false so we do nothing. + unique_ptr<LogEvent> batterySaverOnEvent = + CreateBatterySaverOnEvent(/*timestamp=*/bucketStartTimeNs + 10 * NS_PER_SEC); + StateManager::getInstance().onLogEvent(*batterySaverOnEvent); + EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size()); + EXPECT_EQ(0UL, valueProducer->mCurrentBaseInfo.size()); + + // Bucket status after condition change to true. + valueProducer->onConditionChanged(true, bucketStartTimeNs + 20 * NS_PER_SEC); + // Base for dimension key {} + ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); + std::unordered_map<HashableDimensionKey, std::vector<ValueMetricProducer::BaseInfo>>::iterator + itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); + EXPECT_TRUE(itBase->second[0].hasBase); + EXPECT_EQ(3, itBase->second[0].base.long_value); + EXPECT_TRUE(itBase->second[0].hasCurrentState); + ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::ON, + itBase->second[0].currentState.getValues()[0].mValue.int_value); + // Value for key {{}, -1} + ASSERT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size()); + std::unordered_map<MetricDimensionKey, std::vector<ValueMetricProducer::Interval>>::iterator + it = valueProducer->mCurrentSlicedBucket.begin(); + EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); + ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); + EXPECT_EQ(-1 /*StateTracker::kUnknown*/, + it->first.getStateValuesKey().getValues()[0].mValue.int_value); + EXPECT_FALSE(it->second[0].hasValue); + + // Bucket status after battery saver mode OFF event. + unique_ptr<LogEvent> batterySaverOffEvent = + CreateBatterySaverOffEvent(/*timestamp=*/bucketStartTimeNs + 30 * NS_PER_SEC); + StateManager::getInstance().onLogEvent(*batterySaverOffEvent); + // Base for dimension key {} + ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); + itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); + EXPECT_TRUE(itBase->second[0].hasBase); + EXPECT_EQ(5, itBase->second[0].base.long_value); + EXPECT_TRUE(itBase->second[0].hasCurrentState); + ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::OFF, + itBase->second[0].currentState.getValues()[0].mValue.int_value); + // Value for key {{}, ON} + ASSERT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size()); + it = valueProducer->mCurrentSlicedBucket.begin(); + EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); + ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::ON, + it->first.getStateValuesKey().getValues()[0].mValue.int_value); + EXPECT_TRUE(it->second[0].hasValue); + EXPECT_EQ(2, it->second[0].value.long_value); + + // Pull at end of first bucket. + vector<shared_ptr<LogEvent>> allData; + allData.clear(); + allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket2StartTimeNs, 11)); + valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs); + + EXPECT_EQ(2UL, valueProducer->mPastBuckets.size()); + EXPECT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size()); + // Base for dimension key {} + ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); + itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); + EXPECT_TRUE(itBase->second[0].hasBase); + EXPECT_EQ(11, itBase->second[0].base.long_value); + EXPECT_TRUE(itBase->second[0].hasCurrentState); + ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::OFF, + itBase->second[0].currentState.getValues()[0].mValue.int_value); + + // Bucket 2 status after condition change to false. + valueProducer->onConditionChanged(false, bucket2StartTimeNs + 10 * NS_PER_SEC); + // Base for dimension key {} + ASSERT_EQ(1UL, valueProducer->mCurrentBaseInfo.size()); + itBase = valueProducer->mCurrentBaseInfo.find(DEFAULT_DIMENSION_KEY); + EXPECT_FALSE(itBase->second[0].hasBase); + EXPECT_TRUE(itBase->second[0].hasCurrentState); + ASSERT_EQ(1, itBase->second[0].currentState.getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::OFF, + itBase->second[0].currentState.getValues()[0].mValue.int_value); + // Value for key {{}, OFF} + ASSERT_EQ(3UL, valueProducer->mCurrentSlicedBucket.size()); + it = valueProducer->mCurrentSlicedBucket.begin(); + EXPECT_EQ(0, it->first.getDimensionKeyInWhat().getValues().size()); + ASSERT_EQ(1, it->first.getStateValuesKey().getValues().size()); + EXPECT_EQ(BatterySaverModeStateChanged::OFF, + it->first.getStateValuesKey().getValues()[0].mValue.int_value); + EXPECT_TRUE(it->second[0].hasValue); + EXPECT_EQ(4, it->second[0].value.long_value); + + // Start dump report and check output. + ProtoOutputStream output; + std::set<string> strSet; + valueProducer->onDumpReport(bucket2StartTimeNs + 50 * NS_PER_SEC, + true /* include recent buckets */, true, NO_TIME_CONSTRAINTS, + &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_value_metrics()); + ASSERT_EQ(2, report.value_metrics().data_size()); + + ValueMetricData data = report.value_metrics().data(0); + EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(BatterySaverModeStateChanged::ON, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).values(0).value_long()); + + data = report.value_metrics().data(1); + EXPECT_EQ(util::BATTERY_SAVER_MODE_STATE_CHANGED, data.slice_by_state(0).atom_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(BatterySaverModeStateChanged::OFF, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(6, data.bucket_info(0).values(0).value_long()); + EXPECT_EQ(4, data.bucket_info(1).values(0).value_long()); +} + +/* + * Test bucket splits when condition is unknown. + */ +TEST(ValueMetricProducerTest, TestForcedBucketSplitWhenConditionUnknownSkipsBucket) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition( + pullerManager, metric, + ConditionState::kUnknown); + + // App update event. + int64_t appUpdateTimeNs = bucketStartTimeNs + 1000; + valueProducer->notifyAppUpgrade(appUpdateTimeNs); + + // Check dump report. + ProtoOutputStream output; + std::set<string> strSet; + int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds + valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true, + NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_value_metrics()); + ASSERT_EQ(0, report.value_metrics().data_size()); + ASSERT_EQ(1, report.value_metrics().skipped_size()); + + EXPECT_EQ(NanoToMillis(bucketStartTimeNs), + report.value_metrics().skipped(0).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(appUpdateTimeNs), + report.value_metrics().skipped(0).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); + + auto dropEvent = report.value_metrics().skipped(0).drop_event(0); + EXPECT_EQ(BucketDropReason::CONDITION_UNKNOWN, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis()); +} + } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 06e29d4b5de1..cee83725d075 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -663,6 +663,8 @@ std::unique_ptr<LogEvent> CreateBatterySaverOnEvent(uint64_t timestampNs) { AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::ON); + AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true); + AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); parseStatsEventToLogEvent(statsEvent, logEvent.get()); @@ -674,6 +676,8 @@ std::unique_ptr<LogEvent> CreateBatterySaverOffEvent(uint64_t timestampNs) { AStatsEvent_setAtomId(statsEvent, util::BATTERY_SAVER_MODE_STATE_CHANGED); AStatsEvent_overwriteTimestamp(statsEvent, timestampNs); AStatsEvent_writeInt32(statsEvent, BatterySaverModeStateChanged::OFF); + AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_EXCLUSIVE_STATE, true); + AStatsEvent_addBoolAnnotation(statsEvent, util::ANNOTATION_ID_STATE_NESTED, false); std::unique_ptr<LogEvent> logEvent = std::make_unique<LogEvent>(/*uid=*/0, /*pid=*/0); parseStatsEventToLogEvent(statsEvent, logEvent.get()); diff --git a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp index db402a0dd658..32cecd3b9dbc 100644 --- a/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp +++ b/cmds/statsd/tests/utils/MultiConditionTrigger_test.cpp @@ -50,13 +50,13 @@ TEST(MultiConditionTrigger, TestMultipleConditions) { }); vector<thread> threads; - vector<bool> done(numConditions, false); + vector<int> done(numConditions, 0); int i = 0; for (const string& conditionName : conditionNames) { threads.emplace_back([&done, &conditionName, &trigger, i] { sleep_for(chrono::milliseconds(3)); - done[i] = true; + done[i] = 1; trigger.markComplete(conditionName); }); i++; |