1 /*
2  * Copyright (C) 2016 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 package android.content.pm.split;
17 
18 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
19 import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK;
20 
21 import android.content.pm.PackageParser;
22 import android.content.res.AssetManager;
23 import android.os.Build;
24 
25 import com.android.internal.util.ArrayUtils;
26 
27 import libcore.io.IoUtils;
28 
29 /**
30  * Loads the base and split APKs into a single AssetManager.
31  * @hide
32  */
33 public class DefaultSplitAssetLoader implements SplitAssetLoader {
34     private final String mBaseCodePath;
35     private final String[] mSplitCodePaths;
36     private final int mFlags;
37 
38     private AssetManager mCachedAssetManager;
39 
DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags)40     public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, int flags) {
41         mBaseCodePath = pkg.baseCodePath;
42         mSplitCodePaths = pkg.splitCodePaths;
43         mFlags = flags;
44     }
45 
loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)46     private static void loadApkIntoAssetManager(AssetManager assets, String apkPath, int flags)
47             throws PackageParser.PackageParserException {
48         if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && !PackageParser.isApkPath(apkPath)) {
49             throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK,
50                     "Invalid package file: " + apkPath);
51         }
52 
53         if (assets.addAssetPath(apkPath) == 0) {
54             throw new PackageParser.PackageParserException(
55                     INSTALL_PARSE_FAILED_BAD_MANIFEST,
56                     "Failed adding asset path: " + apkPath);
57         }
58     }
59 
60     @Override
getBaseAssetManager()61     public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException {
62         if (mCachedAssetManager != null) {
63             return mCachedAssetManager;
64         }
65 
66         AssetManager assets = new AssetManager();
67         try {
68             assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69                     Build.VERSION.RESOURCES_SDK_INT);
70             loadApkIntoAssetManager(assets, mBaseCodePath, mFlags);
71 
72             if (!ArrayUtils.isEmpty(mSplitCodePaths)) {
73                 for (String apkPath : mSplitCodePaths) {
74                     loadApkIntoAssetManager(assets, apkPath, mFlags);
75                 }
76             }
77 
78             mCachedAssetManager = assets;
79             assets = null;
80             return mCachedAssetManager;
81         } finally {
82             if (assets != null) {
83                 IoUtils.closeQuietly(assets);
84             }
85         }
86     }
87 
88     @Override
getSplitAssetManager(int splitIdx)89     public AssetManager getSplitAssetManager(int splitIdx)
90             throws PackageParser.PackageParserException {
91         return getBaseAssetManager();
92     }
93 
94     @Override
close()95     public void close() throws Exception {
96         if (mCachedAssetManager != null) {
97             IoUtils.closeQuietly(mCachedAssetManager);
98         }
99     }
100 }
101