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 File testsDir = null; 71 if (buildInfo != null && buildInfo instanceof IDeviceBuildInfo) { 72 testsDir = ((IDeviceBuildInfo) buildInfo).getTestsDir(); 73 if (testsDir != null && testsDir.exists()) { 74 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, "DATA", "app")); 75 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, "DATA", "app", apkBase)); 76 expandedTestDirs.add( 77 FileUtil.getFileForPath(testsDir, "DATA", "priv-app", apkBase)); 78 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, apkBase)); 79 80 // Files in testcases directory imported from env. variable can have a folder 81 // hierarchy, so we search for folder. 82 File testcasesSubDir = FileUtil.findFile(testsDir, apkBase); 83 if (testcasesSubDir != null) { 84 expandedTestDirs.add(testcasesSubDir); 85 } else { 86 // If there doesn't exist a directory named after apkBase, it's possible that 87 // the apk is built output to a different module directory. Therefore, try to 88 // search entire testsDir to locate the apk. 89 // TODO(dshi): Find a better way to locate apk. Ideally we should start with the 90 // test module's directory to avoid false-positive result. 91 expandedTestDirs.add(testsDir); 92 } 93 } 94 } 95 if (altDirBehavior == null) { 96 altDirBehavior = AltDirBehavior.FALLBACK; 97 } 98 if (altDirBehavior == AltDirBehavior.FALLBACK) { 99 // alt dirs are appended after build artifact dirs 100 expandedTestDirs.addAll(dirs); 101 dirs = expandedTestDirs; 102 } else if (altDirBehavior == AltDirBehavior.OVERRIDE) { 103 dirs.addAll(expandedTestDirs); 104 } else { 105 throw new IOException("Missing handler for alt-dir-behavior: " + altDirBehavior); 106 } 107 if (dirs.isEmpty() && !lookupInResource) { 108 throw new IOException( 109 "Provided buildInfo does not contain a valid tests directory and no " + 110 "fallback options were provided"); 111 } 112 113 for (File dir : dirs) { 114 // Recursively search each folder 115 File testAppFile = FileUtil.findFile(dir, apkFileName); 116 if (testAppFile != null && testAppFile.exists()) { 117 return testAppFile; 118 } 119 } 120 if (lookupInResource) { 121 List<String> resourceLookup = new ArrayList<>(); 122 if (deviceSigningKey != null) { 123 resourceLookup.add(String.format("/apks/%s-%s.apk", apkBase, deviceSigningKey)); 124 } 125 resourceLookup.add(String.format("/apks/%s", apkFileName)); 126 File apkTempFile = FileUtil.createTempFile(apkFileName, ".apk"); 127 URL apkUrl = null; 128 for (String path : resourceLookup) { 129 apkUrl = BuildTestsZipUtils.class.getResource(path); 130 if (apkUrl != null) { 131 break; 132 } 133 } 134 if (apkUrl != null) { 135 FileUtil.writeToFile(apkUrl.openStream(), apkTempFile); 136 // since we don't know when the file would be no longer needed, we set the file to 137 // be deleted on VM termination 138 apkTempFile.deleteOnExit(); 139 return apkTempFile; 140 } 141 // If we couldn't find a resource, we delete the tmp file 142 FileUtil.deleteFile(apkTempFile); 143 } 144 145 // Try to stage the files from remote zip files. 146 if (testsDir != null) { 147 File apkFile = buildInfo.stageRemoteFile(apkFileName, testsDir); 148 if (apkFile != null) { 149 return apkFile; 150 } 151 } 152 return null; 153 } 154 } 155