14e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski/* 24e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * Copyright (C) 2016 The Android Open Source Project 34e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * 44e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * Licensed under the Apache License, Version 2.0 (the "License"); 54e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * you may not use this file except in compliance with the License. 64e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * You may obtain a copy of the License at 74e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * 84e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * http://www.apache.org/licenses/LICENSE-2.0 94e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * 104e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * Unless required by applicable law or agreed to in writing, software 114e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * distributed under the License is distributed on an "AS IS" BASIS, 124e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 134e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * See the License for the specific language governing permissions and 144e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * limitations under the License. 154e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski */ 164e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskipackage android.content.pm.split; 174e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 184e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; 194e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; 204e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 211665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinskiimport android.annotation.NonNull; 224e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport android.content.pm.PackageParser; 234e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport android.content.res.AssetManager; 244e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport android.os.Build; 251665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinskiimport android.util.SparseArray; 264e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 274e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport libcore.io.IoUtils; 284e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 294e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport java.util.ArrayList; 304e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskiimport java.util.Collections; 314e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 324e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski/** 334e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * Loads AssetManagers for splits and their dependencies. This SplitAssetLoader implementation 344e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * is to be used when an application opts-in to isolated split loading. 354e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski * @hide 364e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski */ 374e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinskipublic class SplitAssetDependencyLoader 381665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski extends SplitDependencyLoader<PackageParser.PackageParserException> 394e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski implements SplitAssetLoader { 404e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski private final String[] mSplitPaths; 414e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski private final int mFlags; 424e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 431665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski private String[][] mCachedPaths; 444e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski private AssetManager[] mCachedAssetManagers; 454e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 461665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski public SplitAssetDependencyLoader(PackageParser.PackageLite pkg, 471665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski SparseArray<int[]> dependencies, int flags) { 484e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski super(dependencies); 491665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski 501665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski // The base is inserted into index 0, so we need to shift all the splits by 1. 511665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mSplitPaths = new String[pkg.splitCodePaths.length + 1]; 521665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mSplitPaths[0] = pkg.baseCodePath; 531665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski System.arraycopy(pkg.splitCodePaths, 0, mSplitPaths, 1, pkg.splitCodePaths.length); 541665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski 554e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski mFlags = flags; 561665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mCachedPaths = new String[mSplitPaths.length][]; 571665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mCachedAssetManagers = new AssetManager[mSplitPaths.length]; 584e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 594e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 604e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski @Override 614e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski protected boolean isSplitCached(int splitIdx) { 621665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski return mCachedAssetManagers[splitIdx] != null; 634e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 644e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 654e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski private static AssetManager createAssetManagerWithPaths(String[] assetPaths, int flags) 664e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski throws PackageParser.PackageParserException { 674e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski final AssetManager assets = new AssetManager(); 684e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski try { 69408afbf06040ea29d1a9d60e9dc50d1923068de4Romain Guy assets.setConfiguration(0, 0, null, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 704e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski Build.VERSION.RESOURCES_SDK_INT); 714e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 724e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski for (String assetPath : assetPaths) { 734e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski if ((flags & PackageParser.PARSE_MUST_BE_APK) != 0 && 744e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski !PackageParser.isApkPath(assetPath)) { 754e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski throw new PackageParser.PackageParserException(INSTALL_PARSE_FAILED_NOT_APK, 764e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski "Invalid package file: " + assetPath); 774e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 784e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 794e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski if (assets.addAssetPath(assetPath) == 0) { 804e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski throw new PackageParser.PackageParserException( 814e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski INSTALL_PARSE_FAILED_BAD_MANIFEST, 824e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski "Failed adding asset path: " + assetPath); 834e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 844e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 854e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski return assets; 864e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } catch (Throwable e) { 874e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski IoUtils.closeQuietly(assets); 884e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski throw e; 894e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 904e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 914e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 924e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski @Override 931665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski protected void constructSplit(int splitIdx, @NonNull int[] configSplitIndices, 941665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski int parentSplitIdx) throws PackageParser.PackageParserException { 954e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski final ArrayList<String> assetPaths = new ArrayList<>(); 961665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski if (parentSplitIdx >= 0) { 971665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski Collections.addAll(assetPaths, mCachedPaths[parentSplitIdx]); 984e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 994e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 1004e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski assetPaths.add(mSplitPaths[splitIdx]); 1011665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski for (int configSplitIdx : configSplitIndices) { 1021665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski assetPaths.add(mSplitPaths[configSplitIdx]); 1031665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski } 1041665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mCachedPaths[splitIdx] = assetPaths.toArray(new String[assetPaths.size()]); 1051665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski mCachedAssetManagers[splitIdx] = createAssetManagerWithPaths(mCachedPaths[splitIdx], 1064e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski mFlags); 1074e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 1084e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 1094e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski @Override 1104e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski public AssetManager getBaseAssetManager() throws PackageParser.PackageParserException { 1111665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski loadDependenciesForSplit(0); 1121665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski return mCachedAssetManagers[0]; 1134e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 1144e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 1154e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski @Override 1164e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski public AssetManager getSplitAssetManager(int idx) throws PackageParser.PackageParserException { 1171665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski // Since we insert the base at position 0, and PackageParser keeps splits separate from 1181665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski // the base, we need to adjust the index. 1191665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski loadDependenciesForSplit(idx + 1); 1201665d0f028e3a225cb117d3e227bef5c5dace2d4Adam Lesinski return mCachedAssetManagers[idx + 1]; 1214e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 1224e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski 1234e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski @Override 1244e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski public void close() throws Exception { 1254e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski for (AssetManager assets : mCachedAssetManagers) { 1264e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski IoUtils.closeQuietly(assets); 1274e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 1284e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski } 1294e8628157ad0c8c52e74b720eb0328086272ffdaAdam Lesinski} 130