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 com.android.bedstead.nene.devicepolicy;
18 
19 import static android.cts.testapisreflection.TestApisReflectionKt.setProfileOwnerOnOrganizationOwnedDevice;
20 import static android.cts.testapisreflection.TestApisReflectionKt.forceRemoveActiveAdmin;
21 import static android.cts.testapisreflection.TestApisReflectionKt.isRemovingAdmin;
22 import static android.cts.testapisreflection.TestApisReflectionKt.setDeviceOwnerType;
23 import static android.os.Build.VERSION_CODES.R;
24 import static android.os.Build.VERSION_CODES.TIRAMISU;
25 
26 import static com.android.bedstead.permissions.CommonPermissions.MANAGE_PROFILE_AND_DEVICE_OWNERS;
27 
28 import android.annotation.TargetApi;
29 import android.app.admin.DevicePolicyManager;
30 import android.content.ComponentName;
31 import android.os.Build;
32 
33 import com.android.bedstead.nene.TestApis;
34 import com.android.bedstead.nene.exceptions.AdbException;
35 import com.android.bedstead.nene.exceptions.NeneException;
36 import com.android.bedstead.nene.packages.Package;
37 import com.android.bedstead.nene.users.UserReference;
38 import com.android.bedstead.nene.utils.Poll;
39 import com.android.bedstead.nene.utils.ShellCommand;
40 import com.android.bedstead.nene.utils.ShellCommandUtils;
41 import com.android.bedstead.nene.utils.Versions;
42 import com.android.bedstead.permissions.PermissionContext;
43 
44 import java.util.Objects;
45 
46 /**
47  * A reference to a Profile Owner.
48  */
49 public final class ProfileOwner extends DevicePolicyController {
50 
ProfileOwner(UserReference user, Package pkg, ComponentName componentName)51     ProfileOwner(UserReference user,
52             Package pkg,
53             ComponentName componentName) {
54         super(user, pkg, componentName);
55     }
56 
57     /** Returns whether the current profile is organization owned. */
58     @TargetApi(R)
isOrganizationOwned()59     public boolean isOrganizationOwned() {
60         if (!Versions.meetsMinimumSdkVersionRequirement(R)) {
61             return false;
62         }
63 
64         DevicePolicyManager devicePolicyManager =
65                 TestApis.context().androidContextAsUser(mUser).getSystemService(
66                         DevicePolicyManager.class);
67         return devicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile();
68     }
69 
70     /** Sets whether the current profile is organization owned. */
71     @TargetApi(TIRAMISU)
setIsOrganizationOwned(boolean isOrganizationOwned)72     public void setIsOrganizationOwned(boolean isOrganizationOwned) {
73         if (isOrganizationOwned() == isOrganizationOwned) {
74             return; // Nothing to do
75         }
76 
77         Versions.requireMinimumVersion(TIRAMISU);
78 
79         DevicePolicyManager devicePolicyManager =
80                 TestApis.context().androidContextAsUser(mUser).getSystemService(
81                         DevicePolicyManager.class);
82 
83         UserReference user = TestApis.users().system();
84         boolean userSetupComplete = user.getSetupComplete();
85         try {
86             user.setSetupComplete(false);
87 
88             try (PermissionContext p = TestApis.permissions().withPermission(
89                     MANAGE_PROFILE_AND_DEVICE_OWNERS)) {
90                 setProfileOwnerOnOrganizationOwnedDevice(
91                         devicePolicyManager, mComponentName, isOrganizationOwned);
92             }
93         } finally {
94             user.setSetupComplete(userSetupComplete);
95         }
96     }
97 
98     @Override
remove()99     public void remove() {
100         if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
101                 || TestApis.packages().instrumented().isInstantApp()) {
102             removePreS();
103             return;
104         }
105 
106         DevicePolicyManager devicePolicyManager =
107                 TestApis.context().androidContextAsUser(mUser).getSystemService(
108                         DevicePolicyManager.class);
109 
110         try (PermissionContext p =
111                      TestApis.permissions().withPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS)) {
112             forceRemoveActiveAdmin(devicePolicyManager, mComponentName, mUser.id());
113         } catch (SecurityException e) {
114             if (e.getMessage().contains("Attempt to remove non-test admin")
115                     && TEST_APP_APP_COMPONENT_FACTORY.equals(mPackage.appComponentFactory())
116                     && user().parent() == null) {
117                 removeTestApp();
118             } else {
119                 throw e;
120             }
121         }
122 
123         Poll.forValue("Profile Owner",
124                 () -> TestApis.devicePolicy().getProfileOwner(mUser))
125                 .toBeNull()
126                 .errorOnFail().await();
127     }
128 
removePreS()129     private void removePreS() {
130         try {
131             ShellCommand.builderForUser(mUser, "dpm remove-active-admin")
132                     .addOperand(componentName().flattenToShortString())
133                     .validate(ShellCommandUtils::startsWithSuccess)
134                     .execute();
135         } catch (AdbException e) {
136             if (TEST_APP_APP_COMPONENT_FACTORY.equals(mPackage.appComponentFactory())
137                     && user().parent() == null) {
138                 // We can't see why it failed so we'll try the test app version
139                 removeTestApp();
140             } else {
141                 throw new NeneException("Error removing profile owner " + this, e);
142             }
143         }
144     }
145 
146     @Override
toString()147     public String toString() {
148         StringBuilder stringBuilder = new StringBuilder("ProfileOwner{");
149         stringBuilder.append("user=").append(user());
150         stringBuilder.append(", package=").append(pkg());
151         stringBuilder.append(", componentName=").append(componentName());
152         stringBuilder.append("}");
153 
154         return stringBuilder.toString();
155     }
156 
157     @Override
equals(Object obj)158     public boolean equals(Object obj) {
159         if (!(obj instanceof ProfileOwner)) {
160             return false;
161         }
162 
163         ProfileOwner other = (ProfileOwner) obj;
164 
165         return Objects.equals(other.mUser, mUser)
166                 && Objects.equals(other.mPackage, mPackage)
167                 && Objects.equals(other.mComponentName, mComponentName);
168     }
169 }
170