xref: /aosp_15_r20/external/perfetto/src/trace_processor/util/profiler_util.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2020 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 "src/trace_processor/util/profiler_util.h"
18 #include <optional>
19 
20 #include "perfetto/ext/base/string_utils.h"
21 #include "src/trace_processor/storage/trace_storage.h"
22 
23 namespace perfetto {
24 namespace trace_processor {
25 namespace {
26 
27 // Try to extract the package name from a path like:
28 // * /data/app/[packageName]-[randomString]/base.apk
29 // * /data/app/~~[randomStringA]/[packageName]-[randomStringB]/base.apk
30 // The latter is newer (R+), and was added to avoid leaking package names via
31 // mountinfo of incremental apk mounts.
PackageFromApp(base::StringView location)32 std::optional<base::StringView> PackageFromApp(base::StringView location) {
33   location = location.substr(base::StringView("/data/app/").size());
34   size_t start = 0;
35   if (location.at(0) == '~') {
36     size_t slash = location.find('/');
37     if (slash == base::StringView::npos) {
38       return std::nullopt;
39     }
40     start = slash + 1;
41   }
42   size_t end = location.find('/', start + 1);
43   if (end == base::StringView::npos) {
44     return std::nullopt;
45   }
46   location = location.substr(start, end);
47   size_t minus = location.find('-');
48   if (minus == base::StringView::npos) {
49     return std::nullopt;
50   }
51   return location.substr(0, minus);
52 }
53 
54 }  // namespace
55 
PackageFromLocation(TraceStorage * storage,base::StringView location)56 std::optional<std::string> PackageFromLocation(TraceStorage* storage,
57                                                base::StringView location) {
58   // List of some hardcoded apps that do not follow the scheme used in
59   // PackageFromApp. Ask for yours to be added.
60   //
61   // TODO(b/153632336): Get rid of the hardcoded list of system apps.
62   base::StringView sysui(
63       "/system_ext/priv-app/SystemUIGoogle/SystemUIGoogle.apk");
64   if (location.size() >= sysui.size() &&
65       location.substr(0, sysui.size()) == sysui) {
66     return "com.android.systemui";
67   }
68 
69   base::StringView phonesky("/product/priv-app/Phonesky/Phonesky.apk");
70   if (location.size() >= phonesky.size() &&
71       location.substr(0, phonesky.size()) == phonesky) {
72     return "com.android.vending";
73   }
74 
75   base::StringView maps("/product/app/Maps/Maps.apk");
76   if (location.size() >= maps.size() &&
77       location.substr(0, maps.size()) == maps) {
78     return "com.google.android.apps.maps";
79   }
80 
81   base::StringView launcher(
82       "/system_ext/priv-app/NexusLauncherRelease/NexusLauncherRelease.apk");
83   if (location.size() >= launcher.size() &&
84       location.substr(0, launcher.size()) == launcher) {
85     return "com.google.android.apps.nexuslauncher";
86   }
87 
88   base::StringView photos("/product/app/Photos/Photos.apk");
89   if (location.size() >= photos.size() &&
90       location.substr(0, photos.size()) == photos) {
91     return "com.google.android.apps.photos";
92   }
93 
94   base::StringView wellbeing(
95       "/product/priv-app/WellbeingPrebuilt/WellbeingPrebuilt.apk");
96   if (location.size() >= wellbeing.size() &&
97       location.substr(0, wellbeing.size()) == wellbeing) {
98     return "com.google.android.apps.wellbeing";
99   }
100 
101   if (location.find("DevicePersonalizationPrebuilt") !=
102           base::StringView::npos ||
103       location.find("MatchMaker") != base::StringView::npos) {
104     return "com.google.android.as";
105   }
106 
107   if (location.find("DeviceIntelligenceNetworkPrebuilt") !=
108       base::StringView::npos) {
109     return "com.google.android.as.oss";
110   }
111 
112   if (location.find("SettingsIntelligenceGooglePrebuilt") !=
113       base::StringView::npos) {
114     return "com.google.android.settings.intelligence";
115   }
116 
117   base::StringView gm("/product/app/PrebuiltGmail/PrebuiltGmail.apk");
118   if (location.size() >= gm.size() && location.substr(0, gm.size()) == gm) {
119     return "com.google.android.gm";
120   }
121 
122   if (location.find("PrebuiltGmsCore") != base::StringView::npos ||
123       location.find("com.google.android.gms") != base::StringView::npos) {
124     return "com.google.android.gms";
125   }
126 
127   base::StringView velvet("/product/priv-app/Velvet/Velvet.apk");
128   if (location.size() >= velvet.size() &&
129       location.substr(0, velvet.size()) == velvet) {
130     return "com.google.android.googlequicksearchbox";
131   }
132 
133   base::StringView inputmethod(
134       "/product/app/LatinIMEGooglePrebuilt/LatinIMEGooglePrebuilt.apk");
135   if (location.size() >= inputmethod.size() &&
136       location.substr(0, inputmethod.size()) == inputmethod) {
137     return "com.google.android.inputmethod.latin";
138   }
139 
140   base::StringView messaging("/product/app/PrebuiltBugle/PrebuiltBugle.apk");
141   if (location.size() >= messaging.size() &&
142       location.substr(0, messaging.size()) == messaging) {
143     return "com.google.android.apps.messaging";
144   }
145 
146   // Deal with paths to /data/app/...
147 
148   auto extract_package =
149       [storage](base::StringView path) -> std::optional<std::string> {
150     auto package = PackageFromApp(path);
151     if (!package) {
152       PERFETTO_DLOG("Failed to parse %s", path.ToStdString().c_str());
153       storage->IncrementStats(stats::deobfuscate_location_parse_error);
154       return std::nullopt;
155     }
156     return package->ToStdString();
157   };
158 
159   base::StringView data_app("/data/app/");
160   size_t data_app_sz = data_app.size();
161   if (location.substr(0, data_app.size()) == data_app) {
162     return extract_package(location);
163   }
164 
165   // Check for in-memory decompressed dexfile, example prefixes:
166   // * "[anon:dalvik-classes.dex extracted in memory from"
167   // * "/dev/ashmem/dalvik-classes.dex extracted in memory from"
168   // The latter form is for older devices (Android P and before).
169   // We cannot hardcode the filename since it could be for example
170   // "classes2.dex" for multidex apks.
171   base::StringView inmem_dex("dex extracted in memory from /data/app/");
172   size_t match_pos = location.find(inmem_dex);
173   if (match_pos != base::StringView::npos) {
174     auto data_app_path =
175         location.substr(match_pos + inmem_dex.size() - data_app_sz);
176     return extract_package(data_app_path);
177   }
178 
179   return std::nullopt;
180 }
181 
FullyQualifiedDeobfuscatedName(protos::pbzero::ObfuscatedClass::Decoder & cls,protos::pbzero::ObfuscatedMember::Decoder & member)182 std::string FullyQualifiedDeobfuscatedName(
183     protos::pbzero::ObfuscatedClass::Decoder& cls,
184     protos::pbzero::ObfuscatedMember::Decoder& member) {
185   std::string member_deobfuscated_name =
186       member.deobfuscated_name().ToStdString();
187   if (base::Contains(member_deobfuscated_name, '.')) {
188     // Fully qualified name.
189     return member_deobfuscated_name;
190   } else {
191     // Name relative to class.
192     return cls.deobfuscated_name().ToStdString() + "." +
193            member_deobfuscated_name;
194   }
195 }
196 
197 }  // namespace trace_processor
198 }  // namespace perfetto
199