1 /* 2 * Copyright (C) 2015 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 com.android.tradefed.util; 17 18 import com.android.tradefed.build.IBuildInfo; 19 import com.android.tradefed.build.IDeviceBuildInfo; 20 import com.android.tradefed.targetprep.AltDirBehavior; 21 22 import java.io.File; 23 import java.io.IOException; 24 import java.net.URL; 25 import java.util.ArrayList; 26 import java.util.Collections; 27 import java.util.List; 28 29 /** 30 * A helper class for operations related to tests zip generated by Android build system 31 */ 32 public class BuildTestsZipUtils { 33 34 /** 35 * Resolve the actual apk path based on testing artifact information inside build info. 36 * 37 * @param buildInfo build artifact information 38 * @param apkFileName filename of the apk to install 39 * @param altDirs alternative search paths, in addition to path inside {@code buildInfo} 40 * @param altDirBehavior how alternative search paths should be used against path inside 41 * {@code buildInfo}: as fallback, or as override; if unspecified, fallback will be used 42 * @param lookupInResource if the file should be looked up in test harness resources as a final 43 * fallback mechanism 44 * @param deviceSigningKey 45 * @return a {@link File} representing the physical apk file on host or {@code null} if the 46 * file does not exist. 47 */ getApkFile(IBuildInfo buildInfo, String apkFileName, List<File> altDirs, AltDirBehavior altDirBehavior, boolean lookupInResource, String deviceSigningKey)48 public static File getApkFile(IBuildInfo buildInfo, String apkFileName, 49 List<File> altDirs, AltDirBehavior altDirBehavior, 50 boolean lookupInResource, String deviceSigningKey) throws IOException { 51 String apkBase = apkFileName.split("\\.")[0]; 52 53 List<File> dirs = new ArrayList<>(); 54 if (altDirs != null) { 55 for (File dir : altDirs) { 56 dirs.add(dir); 57 // Files in tests zip file will be in DATA/app/, 58 // DATA/app/apk_name or DATA/priv-app/apk_name 59 dirs.add(FileUtil.getFileForPath(dir, "DATA", "app")); 60 dirs.add(FileUtil.getFileForPath(dir, "DATA", "app", apkBase)); 61 dirs.add(FileUtil.getFileForPath(dir, "DATA", "priv-app", apkBase)); 62 // Files in out dir will be in data/app/apk_name 63 dirs.add(FileUtil.getFileForPath(dir, "data", "app", apkBase)); 64 } 65 } 66 // reverse the order so ones provided via command line last can be searched first 67 Collections.reverse(dirs); 68 69 List<File> expandedTestDirs = new ArrayList<>(); 70 if (buildInfo != null && buildInfo instanceof IDeviceBuildInfo) { 71 File testsDir = ((IDeviceBuildInfo) buildInfo).getTestsDir(); 72 if (testsDir != null && testsDir.exists()) { 73 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, "DATA", "app")); 74 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, "DATA", "app", apkBase)); 75 expandedTestDirs.add( 76 FileUtil.getFileForPath(testsDir, "DATA", "priv-app", apkBase)); 77 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, apkBase)); 78 79 // Files in testcases directory imported from env. variable can have a folder 80 // hierarchy, so we search for folder. 81 File testcasesSubDir = FileUtil.findFile(testsDir, apkBase); 82 if (testcasesSubDir != null) { 83 expandedTestDirs.add(testcasesSubDir); 84 } 85 } 86 } 87 if (altDirBehavior == null) { 88 altDirBehavior = AltDirBehavior.FALLBACK; 89 } 90 if (altDirBehavior == AltDirBehavior.FALLBACK) { 91 // alt dirs are appended after build artifact dirs 92 expandedTestDirs.addAll(dirs); 93 dirs = expandedTestDirs; 94 } else if (altDirBehavior == AltDirBehavior.OVERRIDE) { 95 dirs.addAll(expandedTestDirs); 96 } else { 97 throw new IOException("Missing handler for alt-dir-behavior: " + altDirBehavior); 98 } 99 if (dirs.isEmpty() && !lookupInResource) { 100 throw new IOException( 101 "Provided buildInfo does not contain a valid tests directory and no " + 102 "fallback options were provided"); 103 } 104 105 for (File dir : dirs) { 106 // Recursively search each folder 107 File testAppFile = FileUtil.findFile(dir, apkFileName); 108 if (testAppFile != null && testAppFile.exists()) { 109 return testAppFile; 110 } 111 } 112 if (lookupInResource) { 113 List<String> resourceLookup = new ArrayList<>(); 114 if (deviceSigningKey != null) { 115 resourceLookup.add(String.format("/apks/%s-%s.apk", apkBase, deviceSigningKey)); 116 } 117 resourceLookup.add(String.format("/apks/%s", apkFileName)); 118 File apkTempFile = FileUtil.createTempFile(apkFileName, ".apk"); 119 URL apkUrl = null; 120 for (String path : resourceLookup) { 121 apkUrl = BuildTestsZipUtils.class.getResource(path); 122 if (apkUrl != null) { 123 break; 124 } 125 } 126 if (apkUrl != null) { 127 FileUtil.writeToFile(apkUrl.openStream(), apkTempFile); 128 // since we don't know when the file would be no longer needed, we set the file to 129 // be deleted on VM termination 130 apkTempFile.deleteOnExit(); 131 return apkTempFile; 132 } 133 // If we couldn't find a resource, we delete the tmp file 134 FileUtil.deleteFile(apkTempFile); 135 } 136 return null; 137 } 138 } 139