1 /* 2 * Copyright (C) 2016 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.aetest.tradefed.targetprep; 18 19 import static com.android.tradefed.util.BuildTestsZipUtils.getApkFile; 20 21 import com.android.tradefed.build.IBuildInfo; 22 import com.android.tradefed.config.Option; 23 import com.android.tradefed.config.OptionClass; 24 import com.android.tradefed.device.DeviceNotAvailableException; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.targetprep.AltDirBehavior; 28 import com.android.tradefed.targetprep.BaseTargetPreparer; 29 import com.android.tradefed.targetprep.BuildError; 30 import com.android.tradefed.targetprep.ITargetCleaner; 31 import com.android.tradefed.targetprep.ITargetPreparer; 32 import com.android.tradefed.targetprep.TargetSetupError; 33 import com.android.tradefed.targetprep.TestAppInstallSetup; 34 35 import java.io.File; 36 import java.io.IOException; 37 import java.util.ArrayList; 38 import java.util.List; 39 40 /** 41 * A {@link ITargetPreparer} that creates a managed profile in the testing device. 42 * 43 * <p>This was forked off Android Enterprise team's target preparer, where its method of resolving 44 * the test APK was substituted with the platform's implementation. It is also modified to use the 45 * standard TradeFed way of disabling a preparer. The two classes are otherwise the same. 46 */ 47 @OptionClass(alias = "ae-test-create-managed-profile") 48 public class AeTestManagedProfileCreator extends BaseTargetPreparer implements ITargetCleaner { 49 public static final String MANAGED_PROFILE_USER_ID = "managed_profile_user_id"; 50 51 private final TestAppInstallSetup mInstallPreparer = new TestAppInstallSetup(); 52 53 @Option( 54 name = "profile-owner-component", 55 description = "Profile owner component to set; optional") 56 private String mProfileOwnerComponent = null; 57 58 @Option(name = "profile-owner-apk", description = "Profile owner apk path; optional") 59 private String mProfileOwnerApk = null; 60 61 @Option( 62 name = "alt-dir", 63 description = 64 "Alternate directory to look for the profile owner apk if the apk is not in " 65 + "the tests zip file. For each alternate dir, will look in //, " 66 + "//data/app, //DATA/app, //DATA/app/apk_name/ and " 67 + "//DATA/priv-app/apk_name/. Can be repeated. Look for apks in " 68 + "last alt-dir first.") 69 private List<File> mAltDirs = new ArrayList<>(); 70 71 @Option( 72 name = "alt-dir-behavior", 73 description = 74 "The order of alternate directory to be used " 75 + "when searching for apks to install") 76 private AltDirBehavior mAltDirBehavior = AltDirBehavior.FALLBACK; 77 78 @Option( 79 name = "test-app-file-name", 80 description = 81 "the name of an apk file to be installed in work profile. Can be repeated. Items " 82 + "that are directories will have any APKs contained therein, " 83 + "including subdirectories, grouped by package name and installed.") 84 private List<File> mTestFiles = new ArrayList<>(); 85 86 @Option( 87 name = "test-app-alt-dir", 88 description = 89 "Alternate directory to look for the apk if the apk is not in the tests " 90 + "zip file. For each alternate dir, will look in //, //data/app, " 91 + "//DATA/app, //DATA/app/apk_name/ and //DATA/priv-app/apk_name/. " 92 + "Can be repeated. Look for apks in last alt-dir first.") 93 private List<File> mAltTestDirs = new ArrayList<>(); 94 95 /** UserID for user in managed profile. */ 96 private int mManagedProfileUserId; 97 98 /** {@inheritDoc} */ 99 @Override setUp(ITestDevice device, IBuildInfo buildInfo)100 public void setUp(ITestDevice device, IBuildInfo buildInfo) 101 throws TargetSetupError, DeviceNotAvailableException, BuildError { 102 String pmCommand = 103 "pm create-user --profileOf 0 --managed " 104 + "TestProfile_" 105 + System.currentTimeMillis(); 106 String pmCommandOutput = device.executeShellCommand(pmCommand); 107 108 // Extract the id of the new user. 109 String[] pmCmdTokens = pmCommandOutput.split("\\s+"); 110 if (!pmCmdTokens[0].contains("Success:")) { 111 throw new TargetSetupError("Managed profile creation failed."); 112 } 113 mManagedProfileUserId = Integer.parseInt(pmCmdTokens[pmCmdTokens.length - 1]); 114 115 // Start managed profile user. 116 device.startUser(mManagedProfileUserId); 117 118 CLog.i(String.format("New user created: %d", mManagedProfileUserId)); 119 buildInfo.addBuildAttribute(MANAGED_PROFILE_USER_ID, String.valueOf(mManagedProfileUserId)); 120 121 // Install required test APKs in the managed profile 122 installTestApks(device, buildInfo); 123 124 if (mProfileOwnerComponent != null && mProfileOwnerApk != null) { 125 device.installPackageForUser( 126 getApk(device, buildInfo, mProfileOwnerApk), true, mManagedProfileUserId); 127 String command = 128 String.format( 129 "dpm set-profile-owner --user %d %s", 130 mManagedProfileUserId, mProfileOwnerComponent); 131 String commandOutput = device.executeShellCommand(command); 132 String[] cmdTokens = commandOutput.split("\\s+"); 133 if (!cmdTokens[0].contains("Success:")) { 134 throw new RuntimeException( 135 String.format( 136 "Fail to setup %s as profile owner.", mProfileOwnerComponent)); 137 } 138 139 CLog.i( 140 String.format( 141 "%s was set as profile owner of user %d", 142 mProfileOwnerComponent, mManagedProfileUserId)); 143 } 144 /* 145 Commenting this out, as the reboot somehow evaporates the permissions granted to 146 managed profile apps during installation. Creation of apps is not being impacted by this. 147 */ 148 // Reboot device to create the apps in managed profile. 149 // device.reboot(); 150 // device.waitForDeviceAvailable(); 151 } 152 153 /** {@inheritDoc} */ 154 @Override tearDown(ITestDevice testDevice, IBuildInfo buildInfo, Throwable throwable)155 public void tearDown(ITestDevice testDevice, IBuildInfo buildInfo, Throwable throwable) 156 throws DeviceNotAvailableException { 157 mInstallPreparer.tearDown(testDevice, buildInfo, throwable); 158 testDevice.removeUser(mManagedProfileUserId); 159 } 160 installTestApks(ITestDevice device, IBuildInfo buildInfo)161 private void installTestApks(ITestDevice device, IBuildInfo buildInfo) 162 throws DeviceNotAvailableException, TargetSetupError, BuildError { 163 if (mTestFiles.isEmpty()) { 164 return; 165 } 166 CLog.i( 167 String.format( 168 "Installing the following test APKs in user %d: \n%s", 169 mManagedProfileUserId, mTestFiles)); 170 mInstallPreparer.setUserId(mManagedProfileUserId); 171 mInstallPreparer.setShouldGrantPermission(true); 172 for (File file : mTestFiles) { 173 mInstallPreparer.addTestFile(file); 174 } 175 for (File dir : mAltTestDirs) { 176 mInstallPreparer.setAltDir(dir); 177 } 178 mInstallPreparer.setUp(device, buildInfo); 179 } 180 181 /** 182 * Get the {@link File} object that refers to the APK to install. 183 * 184 * <p>This is a replacement of the method with a similar signature in the original class's super 185 * class, so that the above code can align as closely to the original class as possible. 186 */ getApk(ITestDevice device, IBuildInfo buildInfo, String fileName)187 private File getApk(ITestDevice device, IBuildInfo buildInfo, String fileName) 188 throws TargetSetupError { 189 try { 190 File apkFile = 191 getApkFile( 192 buildInfo, 193 mProfileOwnerApk, 194 mAltDirs, 195 mAltDirBehavior, 196 false /* use resource as fallback */, 197 null /* device signing key */); 198 if (apkFile == null) { 199 throw new TargetSetupError( 200 String.format("Test app %s was not found.", mProfileOwnerApk), 201 device.getDeviceDescriptor()); 202 } 203 return apkFile; 204 } catch (IOException e) { 205 throw new TargetSetupError( 206 String.format( 207 "failed to resolve apk path for apk %s in build %s", 208 mProfileOwnerApk, buildInfo.toString()), 209 e, 210 device.getDeviceDescriptor()); 211 } 212 } 213 } 214