1 /* 2 * Copyright (C) 2023 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 17 package com.android.server.sdksandbox.verifier; 18 19 import android.os.Handler; 20 21 import java.io.File; 22 import java.io.IOException; 23 import java.util.ArrayList; 24 import java.util.List; 25 import java.util.Map; 26 27 /** 28 * Handles the loading of dex files for multiple apks to be verified, ensures that a single dex file 29 * is loaded at any time. 30 */ 31 public class SerialDexLoader { 32 private static final String TAG = "SdkSandboxVerifier"; 33 34 private DexParser mParser; 35 private Handler mHandler; 36 private DexLoadResult mDexLoadResult; 37 SerialDexLoader(DexParser parser, Handler handler)38 public SerialDexLoader(DexParser parser, Handler handler) { 39 mParser = parser; 40 mHandler = handler; 41 mDexLoadResult = new DexLoadResult(); 42 } 43 44 /** 45 * Queues all dex files found for an apk for serially loading and analyzing. 46 * 47 * @param apkPathFile path to apk containing one or more dex files 48 * @param packagename packagename associated with the apk 49 * @param verificationHandler object to handle the verification of the loaded dex 50 */ queueApkToLoad( File apkPathFile, String packagename, VerificationHandler verificationHandler)51 public void queueApkToLoad( 52 File apkPathFile, String packagename, VerificationHandler verificationHandler) { 53 54 mHandler.post( 55 () -> { 56 Map<File, List<String>> dexEntries; 57 try { 58 dexEntries = mParser.getDexFilePaths(apkPathFile); 59 } catch (IOException e) { 60 verificationHandler.onVerificationErrorForPackage(e); 61 return; 62 } 63 64 for (Map.Entry<File, List<String>> dexFileEntries : dexEntries.entrySet()) { 65 for (String dexEntry : dexFileEntries.getValue()) { 66 try { 67 mParser.loadDexSymbols( 68 dexFileEntries.getKey(), dexEntry, mDexLoadResult); 69 } catch (IOException e) { 70 verificationHandler.onVerificationErrorForPackage(e); 71 return; 72 } 73 if (!verificationHandler.verify(mDexLoadResult)) { 74 verificationHandler.onVerificationCompleteForPackage(false); 75 return; 76 } 77 } 78 } 79 80 verificationHandler.onVerificationCompleteForPackage(true); 81 }); 82 } 83 84 /** Interface for handling processing of the loaded dex contents */ 85 public interface VerificationHandler { 86 87 /** 88 * Takes in the DexLoadResult and verifies its contents. 89 * 90 * @param result object contains the symbols parsed from the loaded dex file 91 */ verify(DexLoadResult result)92 boolean verify(DexLoadResult result); 93 94 /** 95 * Called when all the loaded dex files have passed verification, or when one has failed. 96 * 97 * @param passed is false if the last loaded dex failed verification, or true if all dexes 98 * passed. 99 */ onVerificationCompleteForPackage(boolean result)100 void onVerificationCompleteForPackage(boolean result); 101 102 /** 103 * Error occurred on verifying. 104 * 105 * @param e exception thrown while attempting to load and verify the apk. 106 */ onVerificationErrorForPackage(Exception e)107 void onVerificationErrorForPackage(Exception e); 108 } 109 110 /** Result class that contains symbols loaded from a DEX file */ 111 public static class DexLoadResult { 112 113 public static final int DEX_MAX_METHOD_COUNT = 65536; 114 115 /** The table of methods referenced by the DEX file. */ 116 private ArrayList<String> mReferencedMethods = new ArrayList<>(DEX_MAX_METHOD_COUNT); 117 118 /** Adds a new method to the referencedMethods table */ addReferencedMethod(String method)119 public void addReferencedMethod(String method) { 120 mReferencedMethods.add(method); 121 } 122 123 /** Returns true if the method string is present in the referencedMethods table */ hasReferencedMethod(String method)124 public boolean hasReferencedMethod(String method) { 125 return mReferencedMethods.contains(method); 126 } 127 128 /** Clears the internal state of DexLoadResult to load next dex file. */ clear()129 public void clear() { 130 mReferencedMethods.clear(); 131 } 132 } 133 } 134