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