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