blob: 050aeb7c5fda1917895e815bca2bfbcdaa64f32b [file] [log] [blame]
Winson9947f1e2019-08-16 10:20:39 -07001/*
2 * Copyright (C) 2019 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
17package android.content.res.loader;
18
19import android.annotation.NonNull;
20import android.content.Context;
21import android.content.pm.ApplicationInfo;
22import android.content.res.ApkAssets;
23import android.content.res.Resources;
24import android.os.ParcelFileDescriptor;
25import android.os.SharedMemory;
26
27import com.android.internal.util.ArrayUtils;
28
29import java.io.Closeable;
30import java.io.IOException;
31
32/**
33 * Provides methods to load resources from an .apk or .arsc file to pass to
34 * {@link Resources#addLoader(ResourceLoader, ResourcesProvider, int)}.
35 *
36 * It is the responsibility of the app to close any instances.
37 */
38public final class ResourcesProvider implements AutoCloseable, Closeable {
39
40 /**
41 * Contains no data, assuming that any resource loading behavior will be handled in the
42 * corresponding {@link ResourceLoader}.
43 */
44 @NonNull
45 public static ResourcesProvider empty() {
46 return new ResourcesProvider(ApkAssets.loadEmptyForLoader());
47 }
48
49 /**
50 * Read from an .apk file descriptor.
51 *
52 * The file descriptor is duplicated and the one passed in may be closed by the application
53 * at any time.
54 */
55 @NonNull
56 public static ResourcesProvider loadFromApk(@NonNull ParcelFileDescriptor fileDescriptor)
57 throws IOException {
58 return new ResourcesProvider(
59 ApkAssets.loadApkForLoader(fileDescriptor.getFileDescriptor()));
60 }
61
62 /**
63 * Read from an .apk file representation in memory.
64 */
65 @NonNull
66 public static ResourcesProvider loadFromApk(@NonNull SharedMemory sharedMemory)
67 throws IOException {
68 return new ResourcesProvider(
69 ApkAssets.loadApkForLoader(sharedMemory.getFileDescriptor()));
70 }
71
72 /**
73 * Read from an .arsc file descriptor.
74 *
75 * The file descriptor is duplicated and the one passed in may be closed by the application
76 * at any time.
77 */
78 @NonNull
79 public static ResourcesProvider loadFromArsc(@NonNull ParcelFileDescriptor fileDescriptor)
80 throws IOException {
81 return new ResourcesProvider(
82 ApkAssets.loadArscForLoader(fileDescriptor.getFileDescriptor()));
83 }
84
85 /**
86 * Read from an .arsc file representation in memory.
87 */
88 @NonNull
89 public static ResourcesProvider loadFromArsc(@NonNull SharedMemory sharedMemory)
90 throws IOException {
91 return new ResourcesProvider(
92 ApkAssets.loadArscForLoader(sharedMemory.getFileDescriptor()));
93 }
94
95 /**
96 * Read from a split installed alongside the application, which may not have been
97 * loaded initially because the application requested isolated split loading.
98 */
99 @NonNull
100 public static ResourcesProvider loadFromSplit(@NonNull Context context,
101 @NonNull String splitName) throws IOException {
102 ApplicationInfo appInfo = context.getApplicationInfo();
103 int splitIndex = ArrayUtils.indexOf(appInfo.splitNames, splitName);
104 if (splitIndex < 0) {
105 throw new IllegalArgumentException("Split " + splitName + " not found");
106 }
107
108 String splitPath = appInfo.getSplitCodePaths()[splitIndex];
109 return new ResourcesProvider(ApkAssets.loadApkForLoader(splitPath));
110 }
111
112
113 @NonNull
114 private final ApkAssets mApkAssets;
115
116 private ResourcesProvider(@NonNull ApkAssets apkAssets) {
117 this.mApkAssets = apkAssets;
118 }
119
120 /** @hide */
121 @NonNull
122 public ApkAssets getApkAssets() {
123 return mApkAssets;
124 }
125
126 @Override
127 public void close() {
128 try {
129 mApkAssets.close();
130 } catch (Throwable ignored) {
131 }
132 }
133
134 @Override
135 protected void finalize() throws Throwable {
136 close();
137 super.finalize();
138 }
139}