1 /*
2 * Copyright (C) 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cstdint>
18 #include <string>
19 #include <string_view>
20 #include <vector>
21
22 #include "perfetto/base/status.h"
23 #include "src/base/test/status_matchers.h"
24 #include "src/trace_redaction/find_package_uid.h"
25 #include "src/trace_redaction/prune_package_list.h"
26 #include "src/trace_redaction/trace_redaction_framework.h"
27 #include "src/trace_redaction/trace_redaction_integration_fixture.h"
28 #include "src/trace_redaction/trace_redactor.h"
29 #include "test/gtest_and_gmock.h"
30
31 #include "protos/perfetto/trace/android/packages_list.gen.h"
32 #include "protos/perfetto/trace/android/packages_list.pbzero.h"
33 #include "protos/perfetto/trace/trace.pbzero.h"
34 #include "protos/perfetto/trace/trace_packet.gen.h"
35 #include "protos/perfetto/trace/trace_packet.pbzero.h"
36
37 namespace perfetto::trace_redaction {
38
39 namespace {
40
41 // Set the package name to "just some package name". If a specific package name
42 // is needed, the test it should overwrite this value.
43 constexpr std::string_view kPackageName =
44 "com.Unity.com.unity.multiplayer.samples.coop";
45 constexpr uint64_t kPackageUid = 10252;
46
47 } // namespace
48
49 class PrunePackageListIntegrationTest
50 : public testing::Test,
51 protected TraceRedactionIntegrationFixure {
52 protected:
SetUp()53 void SetUp() override {
54 context_.package_name = kPackageName;
55
56 trace_redactor_.emplace_collect<FindPackageUid>();
57 trace_redactor_.emplace_transform<PrunePackageList>();
58 }
59
GetPackageInfo(const protos::pbzero::Trace::Decoder & trace) const60 std::vector<protos::gen::PackagesList::PackageInfo> GetPackageInfo(
61 const protos::pbzero::Trace::Decoder& trace) const {
62 std::vector<protos::gen::PackagesList::PackageInfo> packages;
63
64 for (auto packet_it = trace.packet(); packet_it; ++packet_it) {
65 protos::pbzero::TracePacket::Decoder packet(*packet_it);
66
67 if (!packet.has_packages_list()) {
68 continue;
69 }
70
71 protos::pbzero::PackagesList::Decoder list(packet.packages_list());
72
73 for (auto info = list.packages(); info; ++info) {
74 auto& item = packages.emplace_back();
75 item.ParseFromArray(info->data(), info->size());
76 }
77 }
78
79 return packages;
80 }
81
GetPackageNames(const protos::pbzero::Trace::Decoder & trace) const82 std::vector<std::string> GetPackageNames(
83 const protos::pbzero::Trace::Decoder& trace) const {
84 std::vector<std::string> names;
85
86 for (const auto& package : GetPackageInfo(trace)) {
87 if (package.has_name()) {
88 names.push_back(package.name());
89 }
90 }
91
92 return names;
93 }
94
95 Context context_;
96 TraceRedactor trace_redactor_;
97 };
98
99 // It is possible for two packages_list to appear in the trace. The
100 // find_package_uid will stop after the first one is found. Package uids are
101 // appear as n * 1,000,000 where n is some integer. It is also possible for two
102 // packages_list to contain copies of each other - for example
103 // "com.Unity.com.unity.multiplayer.samples.coop" appears in both packages_list.
TEST_F(PrunePackageListIntegrationTest,FindsPackageAndFiltersPackageList)104 TEST_F(PrunePackageListIntegrationTest, FindsPackageAndFiltersPackageList) {
105 auto result = Redact(trace_redactor_, &context_);
106 ASSERT_OK(result) << result.message();
107
108 auto after_raw_trace = LoadRedacted();
109 ASSERT_OK(after_raw_trace) << after_raw_trace.status().message();
110
111 ASSERT_TRUE(context_.package_uid.has_value());
112 ASSERT_EQ(*context_.package_uid, kPackageUid);
113
114 protos::pbzero::Trace::Decoder redacted_trace(after_raw_trace.value());
115 auto packages = GetPackageInfo(redacted_trace);
116
117 ASSERT_EQ(packages.size(), 2u);
118
119 for (const auto& package : packages) {
120 ASSERT_TRUE(package.has_name());
121 ASSERT_EQ(package.name(), kPackageName);
122
123 ASSERT_TRUE(package.has_uid());
124 ASSERT_EQ(NormalizeUid(package.uid()), kPackageUid);
125 }
126 }
127
128 // It is possible for multiple packages to share a uid. The names will appears
129 // across multiple package lists. The only time the package name appears is in
130 // the package list, so there is no way to differentiate these packages (only
131 // the uid is used later), so each entry should remain.
TEST_F(PrunePackageListIntegrationTest,RetainsAllInstancesOfUid)132 TEST_F(PrunePackageListIntegrationTest, RetainsAllInstancesOfUid) {
133 context_.package_name = "com.google.android.networkstack.tethering";
134
135 auto result = Redact(trace_redactor_, &context_);
136 ASSERT_OK(result) << result.message();
137
138 auto after_raw_trace = LoadRedacted();
139 ASSERT_OK(after_raw_trace) << after_raw_trace.status().message();
140
141 protos::pbzero::Trace::Decoder redacted_trace(after_raw_trace.value());
142 auto package_names = GetPackageNames(redacted_trace);
143
144 std::vector<std::string> expected_package_names = {
145 "com.google.android.cellbroadcastservice",
146 "com.google.android.cellbroadcastservice",
147 "com.google.android.networkstack",
148 "com.google.android.networkstack",
149 "com.google.android.networkstack.permissionconfig",
150 "com.google.android.networkstack.permissionconfig",
151 "com.google.android.networkstack.tethering",
152 "com.google.android.networkstack.tethering",
153 };
154
155 // Sort to make compare possible.
156 std::sort(expected_package_names.begin(), expected_package_names.end());
157 std::sort(package_names.begin(), package_names.end());
158
159 ASSERT_TRUE(std::equal(package_names.begin(), package_names.end(),
160 expected_package_names.begin(),
161 expected_package_names.end()));
162 }
163
164 } // namespace perfetto::trace_redaction
165