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