blob: 565ef4b7205886f38188581f552669991dab1e13 [file] [log] [blame]
Makoto Onukicc4bbeb2015-09-17 10:28:24 -07001/*
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 */
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070016package com.android.server.devicepolicy;
17
18import com.android.server.LocalServices;
Makoto Onukia52562c2015-10-01 16:12:31 -070019import com.android.server.SystemService;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070020
Makoto Onukif76b06a2015-09-22 15:03:44 -070021import android.Manifest.permission;
22import android.app.Activity;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070023import android.app.admin.DeviceAdminReceiver;
24import android.app.admin.DevicePolicyManager;
25import android.app.admin.DevicePolicyManagerInternal;
Makoto Onukif76b06a2015-09-22 15:03:44 -070026import android.content.BroadcastReceiver;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070027import android.content.ComponentName;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070028import android.content.pm.PackageManager;
Makoto Onukia31ebbc2015-11-23 17:15:21 -080029import android.net.wifi.WifiInfo;
Makoto Onuki3ab6f2e2015-11-05 13:55:37 -080030import android.os.Build;
31import android.os.Build.VERSION_CODES;
Makoto Onukif76b06a2015-09-22 15:03:44 -070032import android.os.Bundle;
Makoto Onukic8a5a552015-11-19 14:29:12 -080033import android.os.Process;
Makoto Onukib643fb02015-09-22 15:03:44 -070034import android.os.UserHandle;
Makoto Onukia4f11972015-10-01 13:19:58 -070035import android.os.UserManager;
Makoto Onukia31ebbc2015-11-23 17:15:21 -080036import android.test.MoreAsserts;
Makoto Onukib643fb02015-09-22 15:03:44 -070037import android.util.Pair;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070038
39import org.mockito.ArgumentCaptor;
Makoto Onukib643fb02015-09-22 15:03:44 -070040import org.mockito.invocation.InvocationOnMock;
41import org.mockito.stubbing.Answer;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070042
Makoto Onukic8a5a552015-11-19 14:29:12 -080043import java.util.ArrayList;
Makoto Onukib643fb02015-09-22 15:03:44 -070044import java.util.HashMap;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070045import java.util.List;
Makoto Onukib643fb02015-09-22 15:03:44 -070046import java.util.Map;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070047
48import static org.mockito.Matchers.any;
Makoto Onukia52562c2015-10-01 16:12:31 -070049import static org.mockito.Matchers.anyInt;
Makoto Onukif76b06a2015-09-22 15:03:44 -070050import static org.mockito.Matchers.anyString;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070051import static org.mockito.Matchers.eq;
Makoto Onukif76b06a2015-09-22 15:03:44 -070052import static org.mockito.Matchers.isNull;
Makoto Onukib643fb02015-09-22 15:03:44 -070053import static org.mockito.Mockito.doAnswer;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070054import static org.mockito.Mockito.doReturn;
Makoto Onuki1a2cd742015-11-16 13:51:27 -080055import static org.mockito.Mockito.reset;
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070056import static org.mockito.Mockito.times;
57import static org.mockito.Mockito.verify;
58import static org.mockito.Mockito.when;
59
60/**
Makoto Onukif76b06a2015-09-22 15:03:44 -070061 * Tests for DevicePolicyManager( and DevicePolicyManagerService).
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070062 *
63 m FrameworksServicesTests &&
64 adb install \
Makoto Onukic8a5a552015-11-19 14:29:12 -080065 -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070066 adb shell am instrument -e class com.android.server.devicepolicy.DevicePolicyManagerTest \
Makoto Onukic8a5a552015-11-19 14:29:12 -080067 -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070068
69 (mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
70 */
71public class DevicePolicyManagerTest extends DpmTestBase {
Makoto Onukicc4bbeb2015-09-17 10:28:24 -070072 private DpmMockContext mContext;
73 public DevicePolicyManager dpm;
74 public DevicePolicyManagerServiceTestable dpms;
75
76 @Override
77 protected void setUp() throws Exception {
78 super.setUp();
79
80 mContext = getContext();
81
82 when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
83 .thenReturn(true);
84
Makoto Onukia52562c2015-10-01 16:12:31 -070085 initializeDpms();
Makoto Onukif76b06a2015-09-22 15:03:44 -070086
Makoto Onukid932f762015-09-29 16:53:38 -070087 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
88 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
89 setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
Makoto Onuki3ab6f2e2015-11-05 13:55:37 -080090 setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID);
Makoto Onukif76b06a2015-09-22 15:03:44 -070091
Makoto Onukib643fb02015-09-22 15:03:44 -070092 setUpUserManager();
Makoto Onukif76b06a2015-09-22 15:03:44 -070093 }
94
Makoto Onukia52562c2015-10-01 16:12:31 -070095 private void initializeDpms() {
96 // Need clearCallingIdentity() to pass permission checks.
97 final long ident = mContext.binder.clearCallingIdentity();
98 try {
99 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
100
101 dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
102
103 dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY);
104 dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED);
105
106 dpm = new DevicePolicyManagerTestable(mContext, dpms);
107 } finally {
108 mContext.binder.restoreCallingIdentity(ident);
109 }
110 }
111
Makoto Onukib643fb02015-09-22 15:03:44 -0700112 private void setUpUserManager() {
113 // Emulate UserManager.set/getApplicationRestriction().
114 final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
115
116 // UM.setApplicationRestrictions() will save to appRestrictions.
117 doAnswer(new Answer<Void>() {
118 @Override
119 public Void answer(InvocationOnMock invocation) throws Throwable {
120 String pkg = (String) invocation.getArguments()[0];
121 Bundle bundle = (Bundle) invocation.getArguments()[1];
122 UserHandle user = (UserHandle) invocation.getArguments()[2];
123
124 appRestrictions.put(Pair.create(pkg, user), bundle);
125
126 return null;
127 }
128 }).when(mContext.userManager).setApplicationRestrictions(
129 anyString(), any(Bundle.class), any(UserHandle.class));
130
131 // UM.getApplicationRestrictions() will read from appRestrictions.
132 doAnswer(new Answer<Bundle>() {
133 @Override
134 public Bundle answer(InvocationOnMock invocation) throws Throwable {
135 String pkg = (String) invocation.getArguments()[0];
136 UserHandle user = (UserHandle) invocation.getArguments()[1];
137
138 return appRestrictions.get(Pair.create(pkg, user));
139 }
140 }).when(mContext.userManager).getApplicationRestrictions(
141 anyString(), any(UserHandle.class));
142
Makoto Onukid932f762015-09-29 16:53:38 -0700143 // Add the first secondary user.
144 mContext.addUser(DpmMockContext.CALLER_USER_HANDLE, 0);
Makoto Onukib643fb02015-09-22 15:03:44 -0700145 }
146
147 private void setAsProfileOwner(ComponentName admin) {
148 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
149 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
150
Makoto Onukia4f11972015-10-01 13:19:58 -0700151 // PO needs to be an DA.
Makoto Onukib643fb02015-09-22 15:03:44 -0700152 dpm.setActiveAdmin(admin, /* replace =*/ false);
153
154 // Fire!
155 assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
156
157 // Check
Makoto Onuki068c54a2015-10-13 14:34:03 -0700158 assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
Makoto Onukib643fb02015-09-22 15:03:44 -0700159 }
160
161 public void testHasNoFeature() throws Exception {
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700162 when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
163 .thenReturn(false);
164
165 LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
166 new DevicePolicyManagerServiceTestable(mContext, dataDir);
167
168 // If the device has no DPMS feature, it shouldn't register the local service.
169 assertNull(LocalServices.getService(DevicePolicyManagerInternal.class));
170 }
171
172 /**
173 * Caller doesn't have proper permissions.
174 */
175 public void testSetActiveAdmin_SecurityException() {
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700176 // 1. Failure cases.
177
178 // Caller doesn't have MANAGE_DEVICE_ADMINS.
179 try {
Makoto Onukif76b06a2015-09-22 15:03:44 -0700180 dpm.setActiveAdmin(admin1, false);
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700181 fail("Didn't throw SecurityException");
182 } catch (SecurityException expected) {
183 }
184
185 // Caller has MANAGE_DEVICE_ADMINS, but for different user.
186 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
187 try {
Makoto Onukif76b06a2015-09-22 15:03:44 -0700188 dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1);
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700189 fail("Didn't throw SecurityException");
190 } catch (SecurityException expected) {
191 }
192 }
193
Makoto Onukif76b06a2015-09-22 15:03:44 -0700194 /**
195 * Test for:
196 * {@link DevicePolicyManager#setActiveAdmin}
197 * with replace=false and replace=true
198 * {@link DevicePolicyManager#isAdminActive}
199 * {@link DevicePolicyManager#isAdminActiveAsUser}
200 * {@link DevicePolicyManager#getActiveAdmins}
201 * {@link DevicePolicyManager#getActiveAdminsAsUser}
202 */
203 public void testSetActiveAdmin() throws Exception {
204 // 1. Make sure the caller has proper permissions.
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700205 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
206
Makoto Onukif76b06a2015-09-22 15:03:44 -0700207 // 2. Call the API.
208 dpm.setActiveAdmin(admin1, /* replace =*/ false);
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700209
210 // 3. Verify internal calls.
211
212 // Check if the boradcast is sent.
Makoto Onukif76b06a2015-09-22 15:03:44 -0700213 verify(mContext.spiedContext).sendBroadcastAsUser(
214 MockUtils.checkIntentAction(
215 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
216 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
217 verify(mContext.spiedContext).sendBroadcastAsUser(
218 MockUtils.checkIntentAction(
219 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700220 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
221
Makoto Onukif76b06a2015-09-22 15:03:44 -0700222 verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
223 eq(admin1.getPackageName()),
224 eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
225 eq(PackageManager.DONT_KILL_APP),
226 eq(DpmMockContext.CALLER_USER_HANDLE),
227 anyString());
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700228
229 // TODO Verify other calls too.
Makoto Onukif76b06a2015-09-22 15:03:44 -0700230
231 // Make sure it's active admin1.
232 assertTrue(dpm.isAdminActive(admin1));
233 assertFalse(dpm.isAdminActive(admin2));
234 assertFalse(dpm.isAdminActive(admin3));
235
236 // But not admin1 for a different user.
237
238 // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
239 // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
240 mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
241
242 assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
243 assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
244
245 mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
246
247 // Next, add one more admin.
248 // Before doing so, update the application info, now it's enabled.
Makoto Onukia52562c2015-10-01 16:12:31 -0700249 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID,
250 PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
Makoto Onukif76b06a2015-09-22 15:03:44 -0700251
252 dpm.setActiveAdmin(admin2, /* replace =*/ false);
253
254 // Now we have two admins.
255 assertTrue(dpm.isAdminActive(admin1));
256 assertTrue(dpm.isAdminActive(admin2));
257 assertFalse(dpm.isAdminActive(admin3));
258
259 // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
260 // again. (times(1) because it was previously called for admin1)
261 verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
262 eq(admin1.getPackageName()),
263 eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
264 eq(PackageManager.DONT_KILL_APP),
265 eq(DpmMockContext.CALLER_USER_HANDLE),
266 anyString());
267
268 // 4. Add the same admin1 again without replace, which should throw.
269 try {
270 dpm.setActiveAdmin(admin1, /* replace =*/ false);
271 fail("Didn't throw");
272 } catch (IllegalArgumentException expected) {
273 }
274
275 // 5. Add the same admin1 again with replace, which should succeed.
276 dpm.setActiveAdmin(admin1, /* replace =*/ true);
277
278 // TODO make sure it's replaced.
279
280 // 6. Test getActiveAdmins()
281 List<ComponentName> admins = dpm.getActiveAdmins();
282 assertEquals(2, admins.size());
283 assertEquals(admin1, admins.get(0));
284 assertEquals(admin2, admins.get(1));
285
286 // Another user has no admins.
287 mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
288
289 assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
290 dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
291
292 mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
293 }
294
Makoto Onukid932f762015-09-29 16:53:38 -0700295 public void testSetActiveAdmin_multiUsers() throws Exception {
296
297 final int ANOTHER_USER_ID = 100;
298 final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 20456);
299
300 mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
301
302 // Set up pacakge manager for the other user.
303 setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
Makoto Onukid932f762015-09-29 16:53:38 -0700304
305 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
306
307 dpm.setActiveAdmin(admin1, /* replace =*/ false);
308
309 mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
310 dpm.setActiveAdmin(admin2, /* replace =*/ false);
311
312
313 mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
314 assertTrue(dpm.isAdminActive(admin1));
315 assertFalse(dpm.isAdminActive(admin2));
316
317 mMockContext.binder.callingUid = ANOTHER_ADMIN_UID;
318 assertFalse(dpm.isAdminActive(admin1));
319 assertTrue(dpm.isAdminActive(admin2));
320 }
321
Makoto Onukif76b06a2015-09-22 15:03:44 -0700322 /**
323 * Test for:
324 * {@link DevicePolicyManager#setActiveAdmin}
325 * with replace=false
326 */
327 public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
328 // 1. Make sure the caller has proper permissions.
329 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
330
331 dpm.setActiveAdmin(admin1, /* replace =*/ false);
332 assertTrue(dpm.isAdminActive(admin1));
333
334 // Add the same admin1 again without replace, which should throw.
335 try {
336 dpm.setActiveAdmin(admin1, /* replace =*/ false);
337 fail("Didn't throw");
338 } catch (IllegalArgumentException expected) {
339 }
340 }
341
342 /**
343 * Test for:
Makoto Onuki3ab6f2e2015-11-05 13:55:37 -0800344 * {@link DevicePolicyManager#setActiveAdmin} when the admin isn't protected with
345 * BIND_DEVICE_ADMIN.
346 */
347 public void testSetActiveAdmin_permissionCheck() throws Exception {
348 // 1. Make sure the caller has proper permissions.
349 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
350
351 try {
352 dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
353 fail();
354 } catch (IllegalArgumentException expected) {
355 assertTrue(expected.getMessage().contains(permission.BIND_DEVICE_ADMIN));
356 }
357 assertFalse(dpm.isAdminActive(adminNoPerm));
358
359 // Change the target API level to MNC. Now it can be set as DA.
360 setUpPackageManagerForAdmin(adminNoPerm, DpmMockContext.CALLER_UID, null,
361 VERSION_CODES.M);
362 dpm.setActiveAdmin(adminNoPerm, /* replace =*/ false);
363 assertTrue(dpm.isAdminActive(adminNoPerm));
364
365 // TODO Test the "load from the file" case where DA will still be loaded even without
366 // BIND_DEVICE_ADMIN and target API is N.
367 }
368
369 /**
370 * Test for:
Makoto Onukif76b06a2015-09-22 15:03:44 -0700371 * {@link DevicePolicyManager#removeActiveAdmin}
372 */
373 public void testRemoveActiveAdmin_SecurityException() {
374 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
375
376 // Add admin.
377
378 dpm.setActiveAdmin(admin1, /* replace =*/ false);
379
380 assertTrue(dpm.isAdminActive(admin1));
381
382 assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
383
384 // Directly call the DPMS method with a different userid, which should fail.
385 try {
386 dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1);
387 fail("Didn't throw SecurityException");
388 } catch (SecurityException expected) {
389 }
390
391 // Try to remove active admin with a different caller userid should fail too, without
392 // having MANAGE_DEVICE_ADMINS.
393 mContext.callerPermissions.clear();
394
Makoto Onukid932f762015-09-29 16:53:38 -0700395 // Change the caller, and call into DPMS directly with a different user-id.
396
Makoto Onukif76b06a2015-09-22 15:03:44 -0700397 mContext.binder.callingUid = 1234567;
398 try {
Makoto Onukid932f762015-09-29 16:53:38 -0700399 dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
Makoto Onukif76b06a2015-09-22 15:03:44 -0700400 fail("Didn't throw SecurityException");
401 } catch (SecurityException expected) {
402 }
403 }
404
405 /**
406 * Test for:
407 * {@link DevicePolicyManager#removeActiveAdmin}
408 */
Makoto Onukid932f762015-09-29 16:53:38 -0700409 public void testRemoveActiveAdmin_fromDifferentUserWithINTERACT_ACROSS_USERS_FULL() {
Makoto Onukif76b06a2015-09-22 15:03:44 -0700410 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
411
412 // Add admin1.
413
414 dpm.setActiveAdmin(admin1, /* replace =*/ false);
415
416 assertTrue(dpm.isAdminActive(admin1));
417 assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
418
419 // Different user, but should work, because caller has proper permissions.
420 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
Makoto Onukid932f762015-09-29 16:53:38 -0700421
422 // Change the caller, and call into DPMS directly with a different user-id.
Makoto Onukif76b06a2015-09-22 15:03:44 -0700423 mContext.binder.callingUid = 1234567;
Makoto Onukid932f762015-09-29 16:53:38 -0700424
425 dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE);
Makoto Onukif76b06a2015-09-22 15:03:44 -0700426
427 assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
428
429 // TODO DO Still can't be removed in this case.
430 }
431
432 /**
433 * Test for:
434 * {@link DevicePolicyManager#removeActiveAdmin}
435 */
436 public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
437 // Need MANAGE_DEVICE_ADMINS for setActiveAdmin. We'll remove it later.
438 mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
439
440 // Add admin1.
441
442 dpm.setActiveAdmin(admin1, /* replace =*/ false);
443
444 assertTrue(dpm.isAdminActive(admin1));
445 assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
446
447 // Broadcast from saveSettingsLocked().
448 verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
449 MockUtils.checkIntentAction(
450 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
451 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
452
453 // Remove. No permissions, but same user, so it'll work.
454 mContext.callerPermissions.clear();
455 dpm.removeActiveAdmin(admin1);
456
457 final ArgumentCaptor<BroadcastReceiver> brCap =
458 ArgumentCaptor.forClass(BroadcastReceiver.class);
459
460 // Is removing now, but not removed yet.
461 assertTrue(dpm.isAdminActive(admin1));
462 assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
463
464 verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
465 MockUtils.checkIntentAction(
466 DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
467 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
468 isNull(String.class),
469 brCap.capture(),
470 eq(dpms.mHandler),
471 eq(Activity.RESULT_OK),
472 isNull(String.class),
473 isNull(Bundle.class));
474
475 brCap.getValue().onReceive(mContext, null);
476
477 assertFalse(dpm.isAdminActive(admin1));
478 assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
479
480 // Again broadcast from saveSettingsLocked().
481 verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
482 MockUtils.checkIntentAction(
483 DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
484 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
485
486 // TODO Check other internal calls.
Makoto Onukicc4bbeb2015-09-17 10:28:24 -0700487 }
Makoto Onukib643fb02015-09-22 15:03:44 -0700488
489 /**
490 * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
491 * successfully.
492 */
493 public void testSetDeviceOwner() throws Exception {
494 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800495 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukib643fb02015-09-22 15:03:44 -0700496 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
497 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
498
Makoto Onukid932f762015-09-29 16:53:38 -0700499 // In this test, change the caller user to "system".
Makoto Onukib643fb02015-09-22 15:03:44 -0700500 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
501
Makoto Onukid932f762015-09-29 16:53:38 -0700502 // Make sure admin1 is installed on system user.
503 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
Makoto Onukid932f762015-09-29 16:53:38 -0700504
Makoto Onukic8a5a552015-11-19 14:29:12 -0800505 // Check various get APIs.
506 checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ false);
507
Makoto Onukib643fb02015-09-22 15:03:44 -0700508 // DO needs to be an DA.
509 dpm.setActiveAdmin(admin1, /* replace =*/ false);
510
511 // Fire!
Makoto Onukia52562c2015-10-01 16:12:31 -0700512 assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
Makoto Onukib643fb02015-09-22 15:03:44 -0700513
Makoto Onukic8a5a552015-11-19 14:29:12 -0800514 // getDeviceOwnerComponent should return the admin1 component.
515 assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
516 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
517
518 // Check various get APIs.
519 checkGetDeviceOwnerInfoApi(dpm, /* hasDeviceOwner =*/ true);
520
521 // getDeviceOwnerComponent should *NOT* return the admin1 component for other users.
522 mContext.binder.callingUid = DpmMockContext.CALLER_UID;
523 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
524 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
525
526 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
527
Makoto Onuki219bbaf2015-11-12 01:38:47 +0000528 // Verify internal calls.
529 verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
530 eq(admin1.getPackageName()));
531
Makoto Onukib643fb02015-09-22 15:03:44 -0700532 // TODO We should check if the caller has called clearCallerIdentity().
533 verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
534 eq(UserHandle.USER_SYSTEM), eq(false));
535
536 verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
537 MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
538 MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
539
Makoto Onukic8a5a552015-11-19 14:29:12 -0800540 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
Makoto Onukib643fb02015-09-22 15:03:44 -0700541
Makoto Onuki803d6752015-10-30 12:58:39 -0700542 // Try to set a profile owner on the same user, which should fail.
543 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
544 dpm.setActiveAdmin(admin2, /* refreshing= */ true, UserHandle.USER_SYSTEM);
545 try {
546 dpm.setProfileOwner(admin2, "owner-name", UserHandle.USER_SYSTEM);
547 fail("IllegalStateException not thrown");
548 } catch (IllegalStateException expected) {
549 assertTrue("Message was: " + expected.getMessage(),
550 expected.getMessage().contains("already has a device owner"));
551 }
552
Makoto Onukib643fb02015-09-22 15:03:44 -0700553 // TODO Test getDeviceOwnerName() too. To do so, we need to change
554 // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
555 }
556
Makoto Onukic8a5a552015-11-19 14:29:12 -0800557 private void checkGetDeviceOwnerInfoApi(DevicePolicyManager dpm, boolean hasDeviceOwner) {
558 final int origCallingUser = mContext.binder.callingUid;
559 final List origPermissions = new ArrayList(mContext.callerPermissions);
560 mContext.callerPermissions.clear();
561
562 mContext.callerPermissions.add(permission.MANAGE_USERS);
563
564 mContext.binder.callingUid = Process.SYSTEM_UID;
565
566 // TODO Test getDeviceOwnerName() too. To do so, we need to change
567 // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
568 if (hasDeviceOwner) {
569 assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
570 assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
571 assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
572
573 assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
574 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
575 assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
576 } else {
577 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
578 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
579 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
580
581 assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
582 assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
583 assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
584 }
585
586 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
587 if (hasDeviceOwner) {
588 assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
589 assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
590 assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
591
592 assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
593 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
594 assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
595 } else {
596 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
597 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
598 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
599
600 assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
601 assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
602 assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
603 }
604
605 mContext.binder.callingUid = DpmMockContext.CALLER_UID;
606 // Still with MANAGE_USERS.
607 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
608 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
609 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
610
611 if (hasDeviceOwner) {
612 assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
613 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
614 assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
615 } else {
616 assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
617 assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
618 assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
619 }
620
621 mContext.binder.callingUid = Process.SYSTEM_UID;
622 mContext.callerPermissions.remove(permission.MANAGE_USERS);
623 // System can still call "OnAnyUser" without MANAGE_USERS.
624 if (hasDeviceOwner) {
625 assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
626 assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
627 assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
628
629 assertTrue(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
630 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
631 assertEquals(UserHandle.USER_SYSTEM, dpm.getDeviceOwnerUserId());
632 } else {
633 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
634 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
635 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
636
637 assertFalse(dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName()));
638 assertEquals(null, dpm.getDeviceOwnerComponentOnAnyUser());
639 assertEquals(UserHandle.USER_NULL, dpm.getDeviceOwnerUserId());
640 }
641
642 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
643 // Still no MANAGE_USERS.
644 if (hasDeviceOwner) {
645 assertTrue(dpm.isDeviceOwnerApp(admin1.getPackageName()));
646 assertTrue(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
647 assertEquals(admin1, dpm.getDeviceOwnerComponentOnCallingUser());
648 } else {
649 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
650 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
651 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
652 }
653
654 try {
655 dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
656 fail();
657 } catch (SecurityException expected) {
658 }
659 try {
660 dpm.getDeviceOwnerComponentOnAnyUser();
661 fail();
662 } catch (SecurityException expected) {
663 }
664 try {
665 dpm.getDeviceOwnerUserId();
666 fail();
667 } catch (SecurityException expected) {
668 }
669 try {
670 dpm.getDeviceOwnerNameOnAnyUser();
671 fail();
672 } catch (SecurityException expected) {
673 }
674
675 mContext.binder.callingUid = DpmMockContext.CALLER_UID;
676 // Still no MANAGE_USERS.
677 assertFalse(dpm.isDeviceOwnerApp(admin1.getPackageName()));
678 assertFalse(dpm.isDeviceOwnerAppOnCallingUser(admin1.getPackageName()));
679 assertEquals(null, dpm.getDeviceOwnerComponentOnCallingUser());
680
681 try {
682 dpm.isDeviceOwnerAppOnAnyUser(admin1.getPackageName());
683 fail();
684 } catch (SecurityException expected) {
685 }
686 try {
687 dpm.getDeviceOwnerComponentOnAnyUser();
688 fail();
689 } catch (SecurityException expected) {
690 }
691 try {
692 dpm.getDeviceOwnerUserId();
693 fail();
694 } catch (SecurityException expected) {
695 }
696 try {
697 dpm.getDeviceOwnerNameOnAnyUser();
698 fail();
699 } catch (SecurityException expected) {
700 }
701
702 // Restore.
703 mContext.binder.callingUid = origCallingUser;
704 mContext.callerPermissions.addAll(origPermissions);
705 }
706
707
Makoto Onukib643fb02015-09-22 15:03:44 -0700708 /**
709 * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
710 */
711 public void testSetDeviceOwner_noSuchPackage() {
712 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800713 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukib643fb02015-09-22 15:03:44 -0700714 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
715 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
716
717 // Call from a process on the system user.
718 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
719
Makoto Onukib643fb02015-09-22 15:03:44 -0700720 try {
Makoto Onukia52562c2015-10-01 16:12:31 -0700721 dpm.setDeviceOwner(new ComponentName("a.b.c", ".def"));
Makoto Onukib643fb02015-09-22 15:03:44 -0700722 fail("Didn't throw IllegalArgumentException");
723 } catch (IllegalArgumentException expected) {
Makoto Onuki803d6752015-10-30 12:58:39 -0700724 assertTrue("Message was: " + expected.getMessage(),
725 expected.getMessage().contains("Invalid component"));
Makoto Onukib643fb02015-09-22 15:03:44 -0700726 }
727 }
728
729 public void testSetDeviceOwner_failures() throws Exception {
730 // TODO Test more failure cases. Basically test all chacks in enforceCanSetDeviceOwner().
731 }
732
Makoto Onukia52562c2015-10-01 16:12:31 -0700733 public void testClearDeviceOwner() throws Exception {
734 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800735 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukia52562c2015-10-01 16:12:31 -0700736 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
737 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
738
739 // Set admin1 as a DA to the secondary user.
740 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
741
742 dpm.setActiveAdmin(admin1, /* replace =*/ false);
743
744 // Set admin 1 as the DO to the system user.
745
746 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
747 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
748 dpm.setActiveAdmin(admin1, /* replace =*/ false);
749 assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
750
Makoto Onuki219bbaf2015-11-12 01:38:47 +0000751 // Verify internal calls.
752 verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
753 eq(admin1.getPackageName()));
754
Makoto Onukic8a5a552015-11-19 14:29:12 -0800755 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
Makoto Onukia52562c2015-10-01 16:12:31 -0700756
757 // Set up other mocks.
758 when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle());
759
760 // Now call clear.
761 doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUid(
762 eq(admin1.getPackageName()),
763 anyInt());
764 dpm.clearDeviceOwnerApp(admin1.getPackageName());
765
766 // Now DO shouldn't be set.
Makoto Onukic8a5a552015-11-19 14:29:12 -0800767 assertNull(dpm.getDeviceOwnerComponentOnAnyUser());
Makoto Onukia52562c2015-10-01 16:12:31 -0700768
769 // TODO Check other calls.
770 }
771
772 public void testClearDeviceOwner_fromDifferentUser() throws Exception {
773 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800774 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukia52562c2015-10-01 16:12:31 -0700775 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
776 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
777
778 // Set admin1 as a DA to the secondary user.
779 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
780
781 dpm.setActiveAdmin(admin1, /* replace =*/ false);
782
783 // Set admin 1 as the DO to the system user.
784
785 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
786 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
787 dpm.setActiveAdmin(admin1, /* replace =*/ false);
788 assertTrue(dpm.setDeviceOwner(admin1, "owner-name"));
789
Makoto Onuki219bbaf2015-11-12 01:38:47 +0000790 // Verify internal calls.
791 verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
792 eq(admin1.getPackageName()));
793
Makoto Onukic8a5a552015-11-19 14:29:12 -0800794 assertEquals(admin1, dpm.getDeviceOwnerComponentOnAnyUser());
Makoto Onukia52562c2015-10-01 16:12:31 -0700795
796 // Now call clear from the secondary user, which should throw.
797 mContext.binder.callingUid = DpmMockContext.CALLER_UID;
798
799 // Now call clear.
800 doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUid(
801 eq(admin1.getPackageName()),
802 anyInt());
803 try {
804 dpm.clearDeviceOwnerApp(admin1.getPackageName());
805 fail("Didn't throw");
806 } catch (SecurityException e) {
807 assertEquals("clearDeviceOwner can only be called by the device owner", e.getMessage());
808 }
809
Makoto Onukic8a5a552015-11-19 14:29:12 -0800810 // DO shouldn't be removed.
811 assertTrue(dpm.isDeviceManaged());
Makoto Onukia52562c2015-10-01 16:12:31 -0700812 }
813
Makoto Onukib643fb02015-09-22 15:03:44 -0700814 public void testSetProfileOwner() throws Exception {
815 setAsProfileOwner(admin1);
Makoto Onuki803d6752015-10-30 12:58:39 -0700816
817 // Try setting DO on the same user, which should fail.
818 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
819 dpm.setActiveAdmin(admin2, /* refreshing= */ true, DpmMockContext.CALLER_USER_HANDLE);
820 try {
821 dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE);
822 fail("IllegalStateException not thrown");
823 } catch (IllegalStateException expected) {
824 assertTrue("Message was: " + expected.getMessage(),
825 expected.getMessage().contains("already has a profile owner"));
826 }
Makoto Onukib643fb02015-09-22 15:03:44 -0700827 }
828
829 public void testSetProfileOwner_failures() throws Exception {
830 // TODO Test more failure cases. Basically test all chacks in enforceCanSetProfileOwner().
831 }
832
Makoto Onukia52562c2015-10-01 16:12:31 -0700833 public void testGetDeviceOwnerAdminLocked() throws Exception {
834 checkDeviceOwnerWithMultipleDeviceAdmins();
835 }
836
837 private void checkDeviceOwnerWithMultipleDeviceAdmins() throws Exception {
838 // In ths test, we use 3 users (system + 2 secondary users), set some device admins to them,
839 // set admin2 on CALLER_USER_HANDLE as DO, then call getDeviceOwnerAdminLocked() to
840 // make sure it gets the right component from the right user.
841
842 final int ANOTHER_USER_ID = 100;
843 final int ANOTHER_ADMIN_UID = UserHandle.getUid(ANOTHER_USER_ID, 456);
844
845 mMockContext.addUser(ANOTHER_USER_ID, 0); // Add one more user.
846
847 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800848 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukia52562c2015-10-01 16:12:31 -0700849 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
850 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
851
852 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
853
854 // Make sure the admin packge is installed to each user.
855 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
856 setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);
857
858 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
859 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
860
861 setUpPackageManagerForAdmin(admin2, ANOTHER_ADMIN_UID);
862
863
864 // Set active admins to the users.
865 dpm.setActiveAdmin(admin1, /* replace =*/ false);
866 dpm.setActiveAdmin(admin3, /* replace =*/ false);
867
868 dpm.setActiveAdmin(admin1, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
869 dpm.setActiveAdmin(admin2, /* replace =*/ false, DpmMockContext.CALLER_USER_HANDLE);
870
871 dpm.setActiveAdmin(admin2, /* replace =*/ false, ANOTHER_USER_ID);
872
873 // Set DO on the first non-system user.
874 mContext.setUserRunning(DpmMockContext.CALLER_USER_HANDLE, true);
875 assertTrue(dpm.setDeviceOwner(admin2, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
876
Makoto Onukic8a5a552015-11-19 14:29:12 -0800877 assertEquals(admin2, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
Makoto Onukia52562c2015-10-01 16:12:31 -0700878
879 // Then check getDeviceOwnerAdminLocked().
880 assertEquals(admin2, dpms.getDeviceOwnerAdminLocked().info.getComponent());
881 assertEquals(DpmMockContext.CALLER_UID, dpms.getDeviceOwnerAdminLocked().getUid());
882 }
883
884 /**
885 * This essentially tests
886 * {@code DevicePolicyManagerService.findOwnerComponentIfNecessaryLocked()}. (which is private.)
887 *
888 * We didn't use to persist the DO component class name, but now we do, and the above method
889 * finds the right component from a package name upon migration.
890 */
891 public void testDeviceOwnerMigration() throws Exception {
892 checkDeviceOwnerWithMultipleDeviceAdmins();
893
894 // Overwrite the device owner setting and clears the clas name.
895 dpms.mOwners.setDeviceOwner(
896 new ComponentName(admin2.getPackageName(), ""),
897 "owner-name", DpmMockContext.CALLER_USER_HANDLE);
898 dpms.mOwners.writeDeviceOwner();
899
900 // Make sure the DO component name doesn't have a class name.
Makoto Onukic8a5a552015-11-19 14:29:12 -0800901 assertEquals("", dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false).getClassName());
Makoto Onukia52562c2015-10-01 16:12:31 -0700902
903 // Then create a new DPMS to have it load the settings from files.
Makoto Onuki068c54a2015-10-13 14:34:03 -0700904 when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
905 .thenReturn(new Bundle());
Makoto Onukia52562c2015-10-01 16:12:31 -0700906 initializeDpms();
907
908 // Now the DO component name is a full name.
909 // *BUT* because both admin1 and admin2 belong to the same package, we think admin1 is the
910 // DO.
Makoto Onukic8a5a552015-11-19 14:29:12 -0800911 assertEquals(admin1, dpms.getDeviceOwnerComponent(/* callingUserOnly =*/ false));
Makoto Onukia52562c2015-10-01 16:12:31 -0700912 }
913
Makoto Onukib643fb02015-09-22 15:03:44 -0700914 public void testSetGetApplicationRestriction() {
915 setAsProfileOwner(admin1);
916
917 {
918 Bundle rest = new Bundle();
919 rest.putString("KEY_STRING", "Foo1");
920 dpm.setApplicationRestrictions(admin1, "pkg1", rest);
921 }
922
923 {
924 Bundle rest = new Bundle();
925 rest.putString("KEY_STRING", "Foo2");
926 dpm.setApplicationRestrictions(admin1, "pkg2", rest);
927 }
928
929 {
930 Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
931 assertNotNull(returned);
932 assertEquals(returned.size(), 1);
933 assertEquals(returned.get("KEY_STRING"), "Foo1");
934 }
935
936 {
937 Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
938 assertNotNull(returned);
939 assertEquals(returned.size(), 1);
940 assertEquals(returned.get("KEY_STRING"), "Foo2");
941 }
942
943 dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
944 assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
945 }
Makoto Onukia4f11972015-10-01 13:19:58 -0700946
947 public void testSetUserRestriction_asDo() throws Exception {
948 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
Makoto Onukic8a5a552015-11-19 14:29:12 -0800949 mContext.callerPermissions.add(permission.MANAGE_USERS);
Makoto Onukia4f11972015-10-01 13:19:58 -0700950 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
951 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
952
953 // First, set DO.
954
955 // Call from a process on the system user.
956 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
957
958 // Make sure admin1 is installed on system user.
959 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
Makoto Onukia4f11972015-10-01 13:19:58 -0700960
961 // Call.
962 dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
Makoto Onukia52562c2015-10-01 16:12:31 -0700963 assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
Makoto Onukia4f11972015-10-01 13:19:58 -0700964 UserHandle.USER_SYSTEM));
965
Makoto Onuki068c54a2015-10-13 14:34:03 -0700966 DpmTestUtils.assertRestrictions(
967 DpmTestUtils.newRestrictions(),
968 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
969 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -0700970 DpmTestUtils.assertRestrictions(
971 DpmTestUtils.newRestrictions(),
972 dpm.getUserRestrictions(admin1)
973 );
Makoto Onukia4f11972015-10-01 13:19:58 -0700974
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800975 reset(mContext.userManagerInternal);
976
977 dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
978 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
979 eq(UserHandle.USER_SYSTEM),
980 MockUtils.checkUserRestrictions(),
981 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
982 );
983 reset(mContext.userManagerInternal);
984
Makoto Onukia4f11972015-10-01 13:19:58 -0700985 dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800986 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
987 eq(UserHandle.USER_SYSTEM),
988 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
989 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
990 );
991 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -0700992
Makoto Onuki068c54a2015-10-13 14:34:03 -0700993 DpmTestUtils.assertRestrictions(
994 DpmTestUtils.newRestrictions(
Makoto Onuki1a2cd742015-11-16 13:51:27 -0800995 UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
Makoto Onuki068c54a2015-10-13 14:34:03 -0700996 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
997 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -0700998 DpmTestUtils.assertRestrictions(
999 DpmTestUtils.newRestrictions(
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001000 UserManager.DISALLOW_ADD_USER, UserManager.DISALLOW_OUTGOING_CALLS),
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001001 dpm.getUserRestrictions(admin1)
1002 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001003
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001004 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
1005 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1006 eq(UserHandle.USER_SYSTEM),
1007 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
1008 MockUtils.checkUserRestrictions()
1009 );
1010 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -07001011
Makoto Onuki068c54a2015-10-13 14:34:03 -07001012 DpmTestUtils.assertRestrictions(
1013 DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
1014 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
1015 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001016 DpmTestUtils.assertRestrictions(
1017 DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
1018 dpm.getUserRestrictions(admin1)
1019 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001020
1021 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001022 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1023 eq(UserHandle.USER_SYSTEM),
1024 MockUtils.checkUserRestrictions(),
1025 MockUtils.checkUserRestrictions()
1026 );
1027 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -07001028
Makoto Onuki068c54a2015-10-13 14:34:03 -07001029 DpmTestUtils.assertRestrictions(
1030 DpmTestUtils.newRestrictions(),
1031 dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
1032 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001033 DpmTestUtils.assertRestrictions(
1034 DpmTestUtils.newRestrictions(),
1035 dpm.getUserRestrictions(admin1)
1036 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001037
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001038 // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE are PO restrictions, but when
1039 // DO sets them, the scope is global.
1040 dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
1041 reset(mContext.userManagerInternal);
1042 dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1043 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1044 eq(UserHandle.USER_SYSTEM),
1045 MockUtils.checkUserRestrictions(),
1046 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
1047 UserManager.DISALLOW_UNMUTE_MICROPHONE)
1048 );
1049 reset(mContext.userManagerInternal);
1050
1051 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
1052 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1053
1054
1055 // More tests.
1056 dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
1057 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1058 eq(UserHandle.USER_SYSTEM),
1059 MockUtils.checkUserRestrictions(),
1060 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
1061 );
1062 reset(mContext.userManagerInternal);
1063
1064 dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
1065 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1066 eq(UserHandle.USER_SYSTEM),
1067 MockUtils.checkUserRestrictions(),
1068 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
1069 UserManager.DISALLOW_ADD_USER)
1070 );
1071 reset(mContext.userManagerInternal);
1072
1073 dpm.setCameraDisabled(admin1, true);
1074 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1075 eq(UserHandle.USER_SYSTEM),
1076 // DISALLOW_CAMERA will be applied to both local and global.
1077 MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
1078 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
1079 UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
1080 );
1081 reset(mContext.userManagerInternal);
1082
1083 // Set up another DA and let it disable camera. Now DISALLOW_CAMERA will only be applied
1084 // locally.
1085 dpm.setCameraDisabled(admin1, false);
1086 reset(mContext.userManagerInternal);
1087
1088 setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_SYSTEM_USER_UID);
1089 dpm.setActiveAdmin(admin2, /* replace =*/ false, UserHandle.USER_SYSTEM);
1090 dpm.setCameraDisabled(admin2, true);
1091
1092 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1093 eq(UserHandle.USER_SYSTEM),
1094 // DISALLOW_CAMERA will be applied to both local and global.
1095 MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
1096 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
1097 UserManager.DISALLOW_ADD_USER)
1098 );
1099 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -07001100 // TODO Make sure restrictions are written to the file.
1101 }
1102
1103 public void testSetUserRestriction_asPo() {
1104 setAsProfileOwner(admin1);
1105
Makoto Onuki068c54a2015-10-13 14:34:03 -07001106 DpmTestUtils.assertRestrictions(
1107 DpmTestUtils.newRestrictions(),
1108 dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
1109 .ensureUserRestrictions()
1110 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001111
1112 dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001113 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1114 eq(DpmMockContext.CALLER_USER_HANDLE),
1115 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
1116 isNull(Bundle.class)
1117 );
1118 reset(mContext.userManagerInternal);
1119
Makoto Onukia4f11972015-10-01 13:19:58 -07001120 dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001121 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1122 eq(DpmMockContext.CALLER_USER_HANDLE),
1123 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
1124 UserManager.DISALLOW_OUTGOING_CALLS),
1125 isNull(Bundle.class)
1126 );
1127 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -07001128
Makoto Onuki068c54a2015-10-13 14:34:03 -07001129 DpmTestUtils.assertRestrictions(
1130 DpmTestUtils.newRestrictions(
1131 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
1132 UserManager.DISALLOW_OUTGOING_CALLS
1133 ),
1134 dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
1135 .ensureUserRestrictions()
1136 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001137 DpmTestUtils.assertRestrictions(
1138 DpmTestUtils.newRestrictions(
1139 UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
1140 UserManager.DISALLOW_OUTGOING_CALLS
1141 ),
1142 dpm.getUserRestrictions(admin1)
1143 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001144
1145 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001146 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1147 eq(DpmMockContext.CALLER_USER_HANDLE),
1148 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
1149 isNull(Bundle.class)
1150 );
1151 reset(mContext.userManagerInternal);
Makoto Onuki068c54a2015-10-13 14:34:03 -07001152
1153 DpmTestUtils.assertRestrictions(
1154 DpmTestUtils.newRestrictions(
1155 UserManager.DISALLOW_OUTGOING_CALLS
1156 ),
1157 dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
1158 .ensureUserRestrictions()
1159 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001160 DpmTestUtils.assertRestrictions(
1161 DpmTestUtils.newRestrictions(
1162 UserManager.DISALLOW_OUTGOING_CALLS
1163 ),
1164 dpm.getUserRestrictions(admin1)
1165 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001166
1167 dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001168 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1169 eq(DpmMockContext.CALLER_USER_HANDLE),
1170 MockUtils.checkUserRestrictions(),
1171 isNull(Bundle.class)
1172 );
1173 reset(mContext.userManagerInternal);
Makoto Onukia4f11972015-10-01 13:19:58 -07001174
Makoto Onuki068c54a2015-10-13 14:34:03 -07001175 DpmTestUtils.assertRestrictions(
1176 DpmTestUtils.newRestrictions(),
1177 dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
1178 .ensureUserRestrictions()
1179 );
Makoto Onuki3a3092f2015-10-30 11:07:51 -07001180 DpmTestUtils.assertRestrictions(
1181 DpmTestUtils.newRestrictions(),
1182 dpm.getUserRestrictions(admin1)
1183 );
Makoto Onukia4f11972015-10-01 13:19:58 -07001184
Makoto Onuki1a2cd742015-11-16 13:51:27 -08001185 // DISALLOW_ADJUST_VOLUME and DISALLOW_UNMUTE_MICROPHONE can be set by PO too, even
1186 // though when DO sets them they'll be applied globally.
1187 dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
1188 reset(mContext.userManagerInternal);
1189 dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
1190 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1191 eq(DpmMockContext.CALLER_USER_HANDLE),
1192 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
1193 UserManager.DISALLOW_UNMUTE_MICROPHONE),
1194 isNull(Bundle.class)
1195 );
1196 reset(mContext.userManagerInternal);
1197
1198 dpm.setCameraDisabled(admin1, true);
1199 verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
1200 eq(DpmMockContext.CALLER_USER_HANDLE),
1201 MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
1202 UserManager.DISALLOW_ADJUST_VOLUME,
1203 UserManager.DISALLOW_UNMUTE_MICROPHONE),
1204 isNull(Bundle.class)
1205 );
1206 reset(mContext.userManagerInternal);
1207
Makoto Onukia4f11972015-10-01 13:19:58 -07001208 // TODO Make sure restrictions are written to the file.
1209 }
Makoto Onukia31ebbc2015-11-23 17:15:21 -08001210
1211 public void testGetMacAddress() throws Exception {
1212 mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
1213 mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
1214 mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
1215
1216 // In this test, change the caller user to "system".
1217 mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
1218
1219 // Make sure admin1 is installed on system user.
1220 setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
1221
1222 // Test 1. Caller doesn't have DO or DA.
1223 try {
1224 dpm.getWifiMacAddress();
1225 fail();
1226 } catch (SecurityException e) {
1227 MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
1228 }
1229
1230 // DO needs to be an DA.
1231 dpm.setActiveAdmin(admin1, /* replace =*/ false);
1232 assertTrue(dpm.isAdminActive(admin1));
1233
1234 // Test 2. Caller has DA, but not DO.
1235 try {
1236 dpm.getWifiMacAddress();
1237 fail();
1238 } catch (SecurityException e) {
1239 MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
1240 }
1241
1242 // Test 3. Caller has PO, but not DO.
1243 assertTrue(dpm.setProfileOwner(admin1, null, UserHandle.USER_SYSTEM));
1244 try {
1245 dpm.getWifiMacAddress();
1246 fail();
1247 } catch (SecurityException e) {
1248 MoreAsserts.assertContainsRegex("No active admin owned", e.getMessage());
1249 }
1250
1251 // Remove PO.
1252 dpm.clearProfileOwner(admin1);
1253
1254 // Test 4, Caller is DO now.
1255 assertTrue(dpm.setDeviceOwner(admin1, null, UserHandle.USER_SYSTEM));
1256
1257 // 4-1. But no WifiInfo.
1258 assertNull(dpm.getWifiMacAddress());
1259
1260 // 4-2. Returns WifiInfo, but with the default MAC.
1261 when(mContext.wifiManager.getConnectionInfo()).thenReturn(new WifiInfo());
1262 assertNull(dpm.getWifiMacAddress());
1263
1264 // 4-3. With a real MAC address.
1265 final WifiInfo wi = new WifiInfo();
1266 wi.setMacAddress("11:22:33:44:55:66");
1267 when(mContext.wifiManager.getConnectionInfo()).thenReturn(wi);
1268 assertEquals("11:22:33:44:55:66", dpm.getWifiMacAddress());
1269 }
Makoto Onukicc4bbeb2015-09-17 10:28:24 -07001270}