Home | History | Annotate | Download | only in split
      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 
     44     public DefaultSplitAssetLoader(PackageParser.PackageLite pkg, @ParseFlags int flags) {
     45         mBaseCodePath = pkg.baseCodePath;
     46         mSplitCodePaths = pkg.splitCodePaths;
     47         mFlags = flags;
     48     }
     49 
     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
     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
     95     public AssetManager getSplitAssetManager(int splitIdx) throws PackageParserException {
     96         return getBaseAssetManager();
     97     }
     98 
     99     @Override
    100     public void close() throws Exception {
    101         IoUtils.closeQuietly(mCachedAssetManager);
    102     }
    103 }
    104