• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotation.NonNull;
20 
21 import com.android.server.sdksandbox.verifier.SerialDexLoader.DexSymbols;
22 import com.android.tools.smali.dexlib2.DexFileFactory;
23 import com.android.tools.smali.dexlib2.DexFileFactory.DexFileNotFoundException;
24 import com.android.tools.smali.dexlib2.Opcodes;
25 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
26 import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodReference;
27 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
28 
29 import java.io.File;
30 import java.io.IOException;
31 import java.util.ArrayList;
32 import java.util.Enumeration;
33 import java.util.HashMap;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.zip.ZipEntry;
37 import java.util.zip.ZipFile;
38 
39 /**
40  * DEX parser for SDK verification
41  *
42  * @hide
43  */
44 public class DexParserImpl implements DexParser {
45 
46     @Override
getDexFilePaths(@onNull File apkPathFile)47     public List<DexEntry> getDexFilePaths(@NonNull File apkPathFile) throws IOException {
48         ArrayList<File> apkList = new ArrayList<>();
49 
50         // If multi-apk directory, find a base apk and zero or more split apks
51         if (apkPathFile.isDirectory()) {
52             File[] apkFiles = apkPathFile.listFiles();
53             if (apkFiles == null) {
54                 throw new IOException(
55                         "Error reading apk for SDK verification: " + apkPathFile.getAbsolutePath());
56             }
57             for (File apkFile : apkFiles) {
58                 if (apkFile.isFile() && apkFile.getName().endsWith(".apk")) {
59                     apkList.add(apkFile);
60                 }
61             }
62         } else {
63             apkList.add(apkPathFile);
64         }
65 
66         List<DexEntry> dexList = new ArrayList<>();
67 
68         for (File apk : apkList) {
69             try (ZipFile apkZipFile = new ZipFile(apk)) {
70                 Enumeration<? extends ZipEntry> entriesEnumeration = apkZipFile.entries();
71 
72                 while (entriesEnumeration.hasMoreElements()) {
73                     String entryName = entriesEnumeration.nextElement().getName();
74                     if (entryName.endsWith(".dex")) {
75                         dexList.add(new DexEntry(apk, entryName));
76                     }
77                 }
78             } catch (IOException ex) {
79                 throw new IOException(apk.getName() + " is not a valid DEX container file.", ex);
80             }
81         }
82 
83         return dexList;
84     }
85 
86     @Override
loadDexSymbols(File apkFile, String dexName, DexSymbols dexSymbols)87     public void loadDexSymbols(File apkFile, String dexName, DexSymbols dexSymbols)
88             throws IOException {
89         MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry;
90         try {
91             dexEntry =
92                     DexFileFactory.loadDexEntry(
93                             apkFile, dexName, /* exactMatch */ true, Opcodes.getDefault());
94         } catch (DexFileNotFoundException e) {
95             throw new IOException(e);
96         }
97         dexSymbols.clearAndSetDexEntry(apkFile + "/" + dexName);
98 
99         DexBackedDexFile dexFile = dexEntry.getDexFile();
100 
101         for (DexBackedMethodReference method : dexFile.getMethodSection()) {
102             String classname = method.getDefiningClass();
103             String methodString = method.getName() + ";";
104             for (String param : method.getParameterTypes()) {
105                 methodString = methodString + param;
106             }
107             methodString = methodString + method.getReturnType();
108             // remove the ; suffix in the classname before adding it
109             dexSymbols.addReferencedMethod(
110                     classname.substring(0, classname.length() - 1), methodString);
111         }
112     }
113 }
114