1 /*
2 * Copyright (C) 2022 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 <dlfcn.h>
18
19 #include <optional>
20
21 #define LOG_TAG "OverlayManagerImpl"
22
23 #include "android-base/no_destructor.h"
24 #include "androidfw/ResourceTypes.h"
25 #include "core_jni_helpers.h"
26 #include "jni.h"
27
28 namespace android {
29
30 static struct fabricated_overlay_internal_offsets_t {
31 jclass classObject;
32 jfieldID packageName;
33 jfieldID overlayName;
34 jfieldID targetPackageName;
35 jfieldID targetOverlayable;
36 jfieldID entries;
37 } gFabricatedOverlayInternalOffsets;
38
39 static struct fabricated_overlay_internal_entry_offsets_t {
40 jclass classObject;
41 jfieldID resourceName;
42 jfieldID dataType;
43 jfieldID data;
44 jfieldID stringData;
45 jfieldID binaryData;
46 jfieldID configuration;
47 } gFabricatedOverlayInternalEntryOffsets;
48
49 static struct parcel_file_descriptor_offsets_t {
50 jclass classObject;
51 jmethodID getFd;
52 } gParcelFileDescriptorOffsets;
53
54 static struct List_offsets_t {
55 jclass classObject;
56 jmethodID size;
57 jmethodID get;
58 } gListOffsets;
59
60 static struct fabricated_overlay_info_offsets_t {
61 jclass classObject;
62 jmethodID constructor;
63 jfieldID packageName;
64 jfieldID overlayName;
65 jfieldID targetPackageName;
66 jfieldID targetOverlayable;
67 jfieldID path;
68 } gFabricatedOverlayInfoOffsets;
69
70 namespace self_targeting {
71
72 constexpr const char kIOException[] = "java/io/IOException";
73 constexpr const char IllegalArgumentException[] = "java/lang/IllegalArgumentException";
74
75 class DynamicLibraryLoader {
76 public:
DynamicLibraryLoader(JNIEnv * env)77 explicit DynamicLibraryLoader(JNIEnv* env) {
78 /* For SelfTargeting, there are 2 types of files to be handled. One is frro and the other is
79 * idmap. For creating frro/idmap files and reading frro files, it needs libandroid_runtime
80 * to do a shared link to libidmap2. However, libidmap2 contains the codes generated from
81 * google protocol buffer. When libandroid_runtime does a shared link to libidmap2, it will
82 * impact the memory for system_server and zygote(a.k.a. all applications).
83 *
84 * Not all applications need to either create/read frro files or create idmap files all the
85 * time. When the apps apply the SelfTargeting overlay effect, it only needs libandroifw
86 * that is loaded. To use dlopen(libidmap2.so) is to make sure that applications don't
87 * impact themselves' memory by loading libidmap2 until they need to create/read frro files
88 * or create idmap files.
89 */
90 handle_ = dlopen("libidmap2.so", RTLD_NOW);
91 if (handle_ == nullptr) {
92 jniThrowNullPointerException(env);
93 return;
94 }
95
96 createIdmapFileFuncPtr_ =
97 reinterpret_cast<CreateIdmapFileFunc>(dlsym(handle_, "CreateIdmapFile"));
98 if (createIdmapFileFuncPtr_ == nullptr) {
99 jniThrowNullPointerException(env, "The symbol CreateIdmapFile is not found.");
100 return;
101 }
102 getFabricatedOverlayInfoFuncPtr_ = reinterpret_cast<GetFabricatedOverlayInfoFunc>(
103 dlsym(handle_, "GetFabricatedOverlayInfo"));
104 if (getFabricatedOverlayInfoFuncPtr_ == nullptr) {
105 jniThrowNullPointerException(env, "The symbol GetFabricatedOverlayInfo is not found.");
106 return;
107 }
108 createFrroFile_ = reinterpret_cast<CreateFrroFileFunc>(dlsym(handle_, "CreateFrroFile"));
109 if (createFrroFile_ == nullptr) {
110 jniThrowNullPointerException(env, "The symbol CreateFrroFile is not found.");
111 return;
112 }
113 }
114
callCreateFrroFile(std::string & out_error,const std::string & packageName,const std::string & overlayName,const std::string & targetPackageName,const std::optional<std::string> & targetOverlayable,const std::vector<FabricatedOverlayEntryParameters> & entries_params,const std::string & frro_file_path)115 bool callCreateFrroFile(std::string& out_error, const std::string& packageName,
116 const std::string& overlayName, const std::string& targetPackageName,
117 const std::optional<std::string>& targetOverlayable,
118 const std::vector<FabricatedOverlayEntryParameters>& entries_params,
119 const std::string& frro_file_path) {
120 return createFrroFile_(out_error, packageName, overlayName, targetPackageName,
121 targetOverlayable, entries_params, frro_file_path);
122 }
123
callCreateIdmapFile(std::string & out_error,const std::string & targetPath,const std::string & overlayPath,const std::string & idmapPath,const std::string & overlayName,const bool isSystem,const bool isVendor,const bool isProduct,const bool isTargetSignature,const bool isOdm,const bool isOem)124 bool callCreateIdmapFile(std::string& out_error, const std::string& targetPath,
125 const std::string& overlayPath, const std::string& idmapPath,
126 const std::string& overlayName, const bool isSystem,
127 const bool isVendor, const bool isProduct,
128 const bool isTargetSignature, const bool isOdm, const bool isOem) {
129 return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName,
130 isSystem, isVendor, isProduct, isTargetSignature, isOdm,
131 isOem);
132 }
133
callGetFabricatedOverlayInfo(std::string & out_error,const std::string & overlay_path,OverlayManifestInfo & out_overlay_manifest_info)134 bool callGetFabricatedOverlayInfo(std::string& out_error, const std::string& overlay_path,
135 OverlayManifestInfo& out_overlay_manifest_info) {
136 return getFabricatedOverlayInfoFuncPtr_(out_error, overlay_path, out_overlay_manifest_info);
137 }
138
139 explicit operator bool() const {
140 return handle_ != nullptr && createFrroFile_ != nullptr &&
141 createIdmapFileFuncPtr_ != nullptr && getFabricatedOverlayInfoFuncPtr_ != nullptr;
142 }
143
144 DynamicLibraryLoader(const DynamicLibraryLoader&) = delete;
145
146 DynamicLibraryLoader& operator=(const DynamicLibraryLoader&) = delete;
147
~DynamicLibraryLoader()148 ~DynamicLibraryLoader() {
149 if (handle_ != nullptr) {
150 dlclose(handle_);
151 }
152 }
153
154 private:
155 typedef bool (*CreateFrroFileFunc)(
156 std::string& out_error, const std::string& packageName, const std::string& overlayName,
157 const std::string& targetPackageName,
158 const std::optional<std::string>& targetOverlayable,
159 const std::vector<FabricatedOverlayEntryParameters>& entries_params,
160 const std::string& frro_file_path);
161
162 typedef bool (*CreateIdmapFileFunc)(std::string& out_error, const std::string& targetPath,
163 const std::string& overlayPath,
164 const std::string& idmapPath,
165 const std::string& overlayName, const jboolean isSystem,
166 const jboolean isVendor, const jboolean isProduct,
167 const jboolean isSameWithTargetSignature,
168 const jboolean isOdm, const jboolean isOem);
169
170 typedef bool (*GetFabricatedOverlayInfoFunc)(std::string& out_error,
171 const std::string& overlay_path,
172 OverlayManifestInfo& out_overlay_manifest_info);
173
174 void* handle_;
175 CreateFrroFileFunc createFrroFile_;
176 CreateIdmapFileFunc createIdmapFileFuncPtr_;
177 GetFabricatedOverlayInfoFunc getFabricatedOverlayInfoFuncPtr_;
178 };
179
EnsureDynamicLibraryLoader(JNIEnv * env)180 static DynamicLibraryLoader& EnsureDynamicLibraryLoader(JNIEnv* env) {
181 static android::base::NoDestructor<DynamicLibraryLoader> loader(env);
182 return *loader;
183 }
184
getNullableString(JNIEnv * env,jobject object,jfieldID field)185 static std::optional<std::string> getNullableString(JNIEnv* env, jobject object, jfieldID field) {
186 auto javaString = reinterpret_cast<jstring>(env->GetObjectField(object, field));
187 if (javaString == nullptr) {
188 return std::nullopt;
189 }
190
191 const ScopedUtfChars result(env, javaString);
192 if (result.c_str() == nullptr) {
193 return std::nullopt;
194 }
195
196 return std::optional<std::string>{result.c_str()};
197 }
198
getNullableFileDescriptor(JNIEnv * env,jobject object,jfieldID field)199 static std::optional<android::base::borrowed_fd> getNullableFileDescriptor(JNIEnv* env,
200 jobject object,
201 jfieldID field) {
202 auto binaryData = env->GetObjectField(object, field);
203 if (binaryData == nullptr) {
204 return std::nullopt;
205 }
206
207 return env->CallIntMethod(binaryData, gParcelFileDescriptorOffsets.getFd);
208 }
209
CreateFrroFile(JNIEnv * env,jclass,jstring jsFrroFilePath,jobject overlay)210 static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath, jobject overlay) {
211 DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
212 if (!dlLoader) {
213 jniThrowNullPointerException(env, "libidmap2 is not loaded");
214 return;
215 }
216
217 if (overlay == nullptr) {
218 jniThrowNullPointerException(env, "overlay is null");
219 return;
220 }
221 auto jsPackageName =
222 (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.packageName);
223 const ScopedUtfChars packageName(env, jsPackageName);
224 if (packageName.c_str() == nullptr) {
225 jniThrowNullPointerException(env, "packageName is null");
226 return;
227 }
228 auto jsOverlayName =
229 (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.overlayName);
230 const ScopedUtfChars overlayName(env, jsOverlayName);
231 if (overlayName.c_str() == nullptr) {
232 jniThrowNullPointerException(env, "overlayName is null");
233 return;
234 }
235 auto jsTargetPackageName =
236 (jstring)env->GetObjectField(overlay,
237 gFabricatedOverlayInternalOffsets.targetPackageName);
238 const ScopedUtfChars targetPackageName(env, jsTargetPackageName);
239 if (targetPackageName.c_str() == nullptr) {
240 jniThrowNullPointerException(env, "targetPackageName is null");
241 return;
242 }
243 auto overlayable =
244 getNullableString(env, overlay, gFabricatedOverlayInternalOffsets.targetOverlayable);
245 const ScopedUtfChars frroFilePath(env, jsFrroFilePath);
246 if (frroFilePath.c_str() == nullptr) {
247 jniThrowNullPointerException(env, "frroFilePath is null");
248 return;
249 }
250 jobject entries = env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.entries);
251 if (entries == nullptr) {
252 jniThrowNullPointerException(env, "overlay entries is null");
253 return;
254 }
255 const jint size = env->CallIntMethod(entries, gListOffsets.size);
256 ALOGV("frroFilePath = %s, packageName = %s, overlayName = %s, targetPackageName = %s,"
257 " targetOverlayable = %s, size = %d",
258 frroFilePath.c_str(), packageName.c_str(), overlayName.c_str(), targetPackageName.c_str(),
259 overlayable.value_or(std::string()).c_str(), size);
260
261 std::vector<FabricatedOverlayEntryParameters> entries_params;
262 for (jint i = 0; i < size; i++) {
263 jobject entry = env->CallObjectMethod(entries, gListOffsets.get, i);
264 auto jsResourceName = reinterpret_cast<jstring>(
265 env->GetObjectField(entry, gFabricatedOverlayInternalEntryOffsets.resourceName));
266 const ScopedUtfChars resourceName(env, jsResourceName);
267 const auto dataType =
268 env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.dataType);
269
270 // In Java, the data type is int but the maximum value of data Type is less than 0xff.
271 if (dataType >= UCHAR_MAX) {
272 jniThrowException(env, IllegalArgumentException, "Unsupported data type");
273 return;
274 }
275
276 const auto data = env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.data);
277 auto configuration =
278 getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.configuration);
279 auto string_data =
280 getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.stringData);
281 auto binary_data =
282 getNullableFileDescriptor(env, entry,
283 gFabricatedOverlayInternalEntryOffsets.binaryData);
284 entries_params.push_back(
285 FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType,
286 (DataValue)data,
287 string_data.value_or(std::string()), binary_data,
288 configuration.value_or(std::string())});
289 ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s,"
290 " binaryData = %d, configuration = %s",
291 resourceName.c_str(), dataType, data, string_data.value_or(std::string()).c_str(),
292 binary_data.has_value(), configuration.value_or(std::string()).c_str());
293 }
294
295 std::string err_result;
296 if (!dlLoader.callCreateFrroFile(err_result, packageName.c_str(), overlayName.c_str(),
297 targetPackageName.c_str(), overlayable, entries_params,
298 frroFilePath.c_str())) {
299 jniThrowException(env, IllegalArgumentException, err_result.c_str());
300 return;
301 }
302 }
303
CreateIdmapFile(JNIEnv * env,jclass,jstring jsTargetPath,jstring jsOverlayPath,jstring jsIdmapPath,jstring jsOverlayName,jboolean isSystem,jboolean isVendor,jboolean isProduct,jboolean isTargetSignature,jboolean isOdm,jboolean isOem)304 static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPath,
305 jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName,
306 jboolean isSystem, jboolean isVendor, jboolean isProduct,
307 jboolean isTargetSignature, jboolean isOdm, jboolean isOem) {
308 DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
309 if (!dlLoader) {
310 jniThrowNullPointerException(env, "libidmap2 is not loaded");
311 return;
312 }
313
314 const ScopedUtfChars targetPath(env, jsTargetPath);
315 if (targetPath.c_str() == nullptr) {
316 jniThrowNullPointerException(env, "targetPath is null");
317 return;
318 }
319 const ScopedUtfChars overlayPath(env, jsOverlayPath);
320 if (overlayPath.c_str() == nullptr) {
321 jniThrowNullPointerException(env, "overlayPath is null");
322 return;
323 }
324 const ScopedUtfChars idmapPath(env, jsIdmapPath);
325 if (idmapPath.c_str() == nullptr) {
326 jniThrowNullPointerException(env, "idmapPath is null");
327 return;
328 }
329 const ScopedUtfChars overlayName(env, jsOverlayName);
330 if (overlayName.c_str() == nullptr) {
331 jniThrowNullPointerException(env, "overlayName is null");
332 return;
333 }
334 ALOGV("target_path = %s, overlay_path = %s, idmap_path = %s, overlay_name = %s",
335 targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str(), overlayName.c_str());
336
337 std::string err_result;
338 if (!dlLoader.callCreateIdmapFile(err_result, targetPath.c_str(), overlayPath.c_str(),
339 idmapPath.c_str(), overlayName.c_str(),
340 (isSystem == JNI_TRUE), (isVendor == JNI_TRUE),
341 (isProduct == JNI_TRUE), (isTargetSignature == JNI_TRUE),
342 (isOdm == JNI_TRUE), (isOem == JNI_TRUE))) {
343 jniThrowException(env, kIOException, err_result.c_str());
344 return;
345 }
346 }
347
GetFabricatedOverlayInfo(JNIEnv * env,jclass,jstring jsOverlayPath)348 static jobject GetFabricatedOverlayInfo(JNIEnv* env, jclass /* clazz */, jstring jsOverlayPath) {
349 const ScopedUtfChars overlay_path(env, jsOverlayPath);
350 if (overlay_path.c_str() == nullptr) {
351 jniThrowNullPointerException(env, "overlay_path is null");
352 return nullptr;
353 }
354 ALOGV("overlay_path = %s", overlay_path.c_str());
355
356 DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
357 if (!dlLoader) {
358 return nullptr;
359 }
360
361 std::string err_result;
362 OverlayManifestInfo overlay_manifest_info;
363 if (!dlLoader.callGetFabricatedOverlayInfo(err_result, overlay_path.c_str(),
364 overlay_manifest_info) != 0) {
365 jniThrowException(env, kIOException, err_result.c_str());
366 return nullptr;
367 }
368 jobject info = env->NewObject(gFabricatedOverlayInfoOffsets.classObject,
369 gFabricatedOverlayInfoOffsets.constructor);
370 jstring jsOverName = env->NewStringUTF(overlay_manifest_info.name.c_str());
371 jstring jsPackageName = env->NewStringUTF(overlay_manifest_info.package_name.c_str());
372 jstring jsTargetPackage = env->NewStringUTF(overlay_manifest_info.target_package.c_str());
373 jstring jsTargetOverlayable = env->NewStringUTF(overlay_manifest_info.target_name.c_str());
374 env->SetObjectField(info, gFabricatedOverlayInfoOffsets.overlayName, jsOverName);
375 env->SetObjectField(info, gFabricatedOverlayInfoOffsets.packageName, jsPackageName);
376 env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetPackageName, jsTargetPackage);
377 env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetOverlayable, jsTargetOverlayable);
378 env->SetObjectField(info, gFabricatedOverlayInfoOffsets.path, jsOverlayPath);
379 return info;
380 }
381
382 } // namespace self_targeting
383
384 // JNI registration.
385 static const JNINativeMethod gOverlayManagerMethods[] = {
386 {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V",
387 reinterpret_cast<void*>(self_targeting::CreateFrroFile)},
388 {"createIdmapFile",
389 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZZ)V",
390 reinterpret_cast<void*>(self_targeting::CreateIdmapFile)},
391 {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;",
392 reinterpret_cast<void*>(self_targeting::GetFabricatedOverlayInfo)},
393 };
394
register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv * env)395 int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) {
396 jclass ListClass = FindClassOrDie(env, "java/util/List");
397 gListOffsets.classObject = MakeGlobalRefOrDie(env, ListClass);
398 gListOffsets.size = GetMethodIDOrDie(env, gListOffsets.classObject, "size", "()I");
399 gListOffsets.get =
400 GetMethodIDOrDie(env, gListOffsets.classObject, "get", "(I)Ljava/lang/Object;");
401
402 jclass fabricatedOverlayInternalClass =
403 FindClassOrDie(env, "android/os/FabricatedOverlayInternal");
404 gFabricatedOverlayInternalOffsets.classObject =
405 MakeGlobalRefOrDie(env, fabricatedOverlayInternalClass);
406 gFabricatedOverlayInternalOffsets.packageName =
407 GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "packageName",
408 "Ljava/lang/String;");
409 gFabricatedOverlayInternalOffsets.overlayName =
410 GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "overlayName",
411 "Ljava/lang/String;");
412 gFabricatedOverlayInternalOffsets.targetPackageName =
413 GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetPackageName",
414 "Ljava/lang/String;");
415 gFabricatedOverlayInternalOffsets.targetOverlayable =
416 GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetOverlayable",
417 "Ljava/lang/String;");
418 gFabricatedOverlayInternalOffsets.entries =
419 GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "entries",
420 "Ljava/util/List;");
421
422 jclass fabricatedOverlayInternalEntryClass =
423 FindClassOrDie(env, "android/os/FabricatedOverlayInternalEntry");
424 gFabricatedOverlayInternalEntryOffsets.classObject =
425 MakeGlobalRefOrDie(env, fabricatedOverlayInternalEntryClass);
426 gFabricatedOverlayInternalEntryOffsets.resourceName =
427 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "resourceName",
428 "Ljava/lang/String;");
429 gFabricatedOverlayInternalEntryOffsets.dataType =
430 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "dataType",
431 "I");
432 gFabricatedOverlayInternalEntryOffsets.data =
433 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "data", "I");
434 gFabricatedOverlayInternalEntryOffsets.stringData =
435 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "stringData",
436 "Ljava/lang/String;");
437 gFabricatedOverlayInternalEntryOffsets.binaryData =
438 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "binaryData",
439 "Landroid/os/ParcelFileDescriptor;");
440 gFabricatedOverlayInternalEntryOffsets.configuration =
441 GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
442 "configuration", "Ljava/lang/String;");
443
444 jclass parcelFileDescriptorClass =
445 android::FindClassOrDie(env, "android/os/ParcelFileDescriptor");
446 gParcelFileDescriptorOffsets.classObject = MakeGlobalRefOrDie(env, parcelFileDescriptorClass);
447 gParcelFileDescriptorOffsets.getFd =
448 GetMethodIDOrDie(env, gParcelFileDescriptorOffsets.classObject, "getFd", "()I");
449
450 jclass fabricatedOverlayInfoClass = FindClassOrDie(env, "android/os/FabricatedOverlayInfo");
451 gFabricatedOverlayInfoOffsets.classObject = MakeGlobalRefOrDie(env, fabricatedOverlayInfoClass);
452 gFabricatedOverlayInfoOffsets.constructor =
453 GetMethodIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "<init>", "()V");
454 gFabricatedOverlayInfoOffsets.packageName =
455 GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "packageName",
456 "Ljava/lang/String;");
457 gFabricatedOverlayInfoOffsets.overlayName =
458 GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "overlayName",
459 "Ljava/lang/String;");
460 gFabricatedOverlayInfoOffsets.targetPackageName =
461 GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetPackageName",
462 "Ljava/lang/String;");
463 gFabricatedOverlayInfoOffsets.targetOverlayable =
464 GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetOverlayable",
465 "Ljava/lang/String;");
466 gFabricatedOverlayInfoOffsets.path =
467 GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "path",
468 "Ljava/lang/String;");
469
470 return RegisterMethodsOrDie(env, "com/android/internal/content/om/OverlayManagerImpl",
471 gOverlayManagerMethods, NELEM(gOverlayManagerMethods));
472 }
473
474 } // namespace android
475