1 /* 2 * Copyright (C) 2021 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 android.compat.testing; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.INativeDevice; 23 import com.android.tradefed.util.CommandResult; 24 import com.android.tradefed.util.CommandStatus; 25 import com.android.tradefed.util.FileUtil; 26 27 import com.google.common.collect.ImmutableList; 28 import com.google.common.collect.ImmutableSet; 29 30 import org.jf.dexlib2.DexFileFactory; 31 import org.jf.dexlib2.Opcodes; 32 import org.jf.dexlib2.dexbacked.DexBackedDexFile; 33 import org.jf.dexlib2.iface.ClassDef; 34 import org.jf.dexlib2.iface.MultiDexContainer; 35 36 import java.io.File; 37 import java.io.IOException; 38 import java.util.Objects; 39 40 /** 41 * Testing utilities for parsing *CLASSPATH environ variables on a test device. 42 */ 43 public final class Classpaths { 44 Classpaths()45 private Classpaths() { 46 } 47 48 public enum ClasspathType { 49 BOOTCLASSPATH, 50 DEX2OATBOOTCLASSPATH, 51 SYSTEMSERVERCLASSPATH, 52 } 53 54 /** Returns on device filepaths to the jars that are part of a given classpath. */ getJarsOnClasspath(INativeDevice device, ClasspathType classpath)55 public static ImmutableList<String> getJarsOnClasspath(INativeDevice device, 56 ClasspathType classpath) throws DeviceNotAvailableException { 57 CommandResult shellResult = device.executeShellV2Command("echo $" + classpath); 58 assertThat(shellResult.getStatus()).isEqualTo(CommandStatus.SUCCESS); 59 assertThat(shellResult.getExitCode()).isEqualTo(0); 60 61 String value = shellResult.getStdout().trim(); 62 assertThat(value).isNotEmpty(); 63 return ImmutableList.copyOf(value.split(":")); 64 } 65 66 /** Returns classes defined a given jar file on the test device. */ getClassDefsFromJar(INativeDevice device, String remoteJarPath)67 public static ImmutableSet<ClassDef> getClassDefsFromJar(INativeDevice device, 68 String remoteJarPath) throws DeviceNotAvailableException, IOException { 69 File jar = null; 70 try { 71 jar = device.pullFile(remoteJarPath); 72 if (jar == null) { 73 throw new IllegalStateException("could not pull remote file " + remoteJarPath); 74 } 75 MultiDexContainer<? extends DexBackedDexFile> container = 76 DexFileFactory.loadDexContainer(jar, Opcodes.getDefault()); 77 ImmutableSet.Builder<ClassDef> set = ImmutableSet.builder(); 78 for (String dexName : container.getDexEntryNames()) { 79 set.addAll(Objects.requireNonNull(container.getEntry(dexName)).getClasses()); 80 } 81 return set.build(); 82 } finally { 83 FileUtil.deleteFile(jar); 84 } 85 } 86 87 } 88