Make ENSURE_VERIFY_APPS global even when set by PO.
Currently only device owner can set global user restrictions.
With this CL ENSURE_VERIFY_APPS will be global no matter who
enforces it, DO or PO.
To make it possible for system apps to check who enforces a
particular restriction in this case a new API method is added
to UserManager: getUserRestrictionSources which returns a list
of users who enforce the restriction.
Bug:31000521
Test: cts-tradefed run cts -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.UserRestrictionsTest (ag/1732744)
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
Test: runtest --path frameworks/base/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java
Test: installed M on a Nexus5x device, created a managed profile with some user restrictions, and checked that after upgrading M->O all restrictions are preserved and split correctly into base, global and local.
Change-Id: I543d3ec9ef0cf2b730da6f7406021c0bba43b785
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index e68895e..af9caf2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,6 +15,10 @@
*/
package com.android.server.devicepolicy;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
+
import android.Manifest.permission;
import android.app.Activity;
import android.app.admin.DeviceAdminReceiver;
@@ -39,6 +43,7 @@
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.test.MoreAsserts;
@@ -928,9 +933,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions()
- );
+ eq(null),
+ eq(true), eq(CAMERA_NOT_DISABLED));
assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
@@ -1287,7 +1291,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
@@ -1296,21 +1301,21 @@
}
assertNoDeviceOwnerRestrictions();
+ reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1328,8 +1333,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- MockUtils.checkUserRestrictions()
- );
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1345,8 +1349,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions()
- );
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
assertNoDeviceOwnerRestrictions();
@@ -1358,42 +1361,38 @@
dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
- UserManager.DISALLOW_UNMUTE_MICROPHONE)
- );
+ UserManager.DISALLOW_UNMUTE_MICROPHONE),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-
+ reset(mContext.userManagerInternal);
// More tests.
dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
- );
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- MockUtils.checkUserRestrictions(),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
// DISALLOW_CAMERA will be applied to both local and global.
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_DISABLED_GLOBALLY));
reset(mContext.userManagerInternal);
// Set up another DA and let it disable camera. Now DISALLOW_CAMERA will only be applied
@@ -1407,11 +1406,10 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
- // DISALLOW_CAMERA will be applied to both local and global.
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+ // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
- UserManager.DISALLOW_ADD_USER)
- );
+ UserManager.DISALLOW_ADD_USER),
+ eq(true), eq(CAMERA_DISABLED_LOCALLY));
reset(mContext.userManagerInternal);
// TODO Make sure restrictions are written to the file.
}
@@ -1429,8 +1427,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1438,8 +1435,7 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1462,8 +1458,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1484,8 +1479,7 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
DpmTestUtils.assertRestrictions(
@@ -1507,18 +1501,15 @@
eq(DpmMockContext.CALLER_USER_HANDLE),
MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_NOT_DISABLED));
reset(mContext.userManagerInternal);
dpm.setCameraDisabled(admin1, true);
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(DpmMockContext.CALLER_USER_HANDLE),
- MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
- UserManager.DISALLOW_ADJUST_VOLUME,
+ MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE),
- isNull(Bundle.class)
- );
+ eq(false), eq(CAMERA_DISABLED_LOCALLY));
reset(mContext.userManagerInternal);
// TODO Make sure restrictions are written to the file.
@@ -1558,7 +1549,8 @@
verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(defaultRestrictions),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
@@ -1600,7 +1592,8 @@
verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
eq(UserHandle.USER_SYSTEM),
MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
- MockUtils.checkUserRestrictions()
+ eq(true) /* isDeviceOwner */,
+ eq(CAMERA_NOT_DISABLED)
);
reset(mContext.userManagerInternal);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 11f9ebb..480be2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,13 +16,16 @@
package com.android.server.pm;
+import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions;
+import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions;
+
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.devicepolicy.DpmTestUtils;
+import android.util.SparseArray;
/**
* Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
@@ -49,14 +52,14 @@
public void testIsEmpty() {
assertTrue(UserRestrictionsUtils.isEmpty(null));
assertTrue(UserRestrictionsUtils.isEmpty(new Bundle()));
- assertFalse(UserRestrictionsUtils.isEmpty(DpmTestUtils.newRestrictions("a")));
+ assertFalse(UserRestrictionsUtils.isEmpty(newRestrictions("a")));
}
public void testClone() {
Bundle in = new Bundle();
Bundle out = UserRestrictionsUtils.clone(in);
assertNotSame(in, out);
- DpmTestUtils.assertRestrictions(out, new Bundle());
+ assertRestrictions(out, new Bundle());
out = UserRestrictionsUtils.clone(null);
assertNotNull(out);
@@ -64,16 +67,16 @@
}
public void testMerge() {
- Bundle a = DpmTestUtils.newRestrictions("a", "d");
- Bundle b = DpmTestUtils.newRestrictions("b", "d", "e");
+ Bundle a = newRestrictions("a", "d");
+ Bundle b = newRestrictions("b", "d", "e");
UserRestrictionsUtils.merge(a, b);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+ assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
UserRestrictionsUtils.merge(a, null);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+ assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
try {
UserRestrictionsUtils.merge(a, a);
@@ -114,25 +117,32 @@
final Bundle local = new Bundle();
final Bundle global = new Bundle();
- UserRestrictionsUtils.sortToGlobalAndLocal(null, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
+ UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
- UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, global, local);
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
+ UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
assertEquals(0, global.size());
assertEquals(0, local.size());
- UserRestrictionsUtils.sortToGlobalAndLocal(DpmTestUtils.newRestrictions(
+ // Restrictions set by DO.
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
UserManager.DISALLOW_USB_FILE_TRANSFER,
UserManager.DISALLOW_CONFIG_TETHERING,
UserManager.DISALLOW_OUTGOING_BEAM,
- UserManager.DISALLOW_APPS_CONTROL
- ), global, local);
+ UserManager.DISALLOW_APPS_CONTROL,
+ UserManager.ENSURE_VERIFY_APPS
+ ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+ assertRestrictions(newRestrictions(
+ // This one is global no matter who sets it.
+ UserManager.ENSURE_VERIFY_APPS,
+
// These can be set by PO too, but when DO sets them, they're global.
UserManager.DISALLOW_ADJUST_VOLUME,
UserManager.DISALLOW_UNMUTE_MICROPHONE,
@@ -142,11 +152,117 @@
UserManager.DISALLOW_CONFIG_TETHERING
), global);
- DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+ assertRestrictions(newRestrictions(
// They can be set by both DO/PO.
UserManager.DISALLOW_OUTGOING_BEAM,
UserManager.DISALLOW_APPS_CONTROL
), local);
+
+ local.clear();
+ global.clear();
+
+ // Restrictions set by PO.
+ UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE,
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_CONFIG_TETHERING,
+ UserManager.DISALLOW_OUTGOING_BEAM,
+ UserManager.DISALLOW_APPS_CONTROL,
+ UserManager.ENSURE_VERIFY_APPS
+ ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+
+ assertRestrictions(newRestrictions(
+ // This one is global no matter who sets it.
+ UserManager.ENSURE_VERIFY_APPS
+ ), global);
+
+ assertRestrictions(newRestrictions(
+ // These can be set by PO too, but when PO sets them, they're local.
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_UNMUTE_MICROPHONE,
+
+ // They can be set by both DO/PO.
+ UserManager.DISALLOW_OUTGOING_BEAM,
+ UserManager.DISALLOW_APPS_CONTROL,
+
+ // These can only be set by DO.
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_CONFIG_TETHERING
+ ), local);
+
+ }
+
+ public void testSortToLocalAndGlobalWithCameraDisabled() {
+ final Bundle local = new Bundle();
+ final Bundle global = new Bundle();
+
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+ UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+ assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+ assertEquals(0, local.size());
+ global.clear();
+
+ UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+ UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+ assertEquals(0, global.size());
+ assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
+ }
+
+ public void testMergeAll() {
+ SparseArray<Bundle> restrictions = new SparseArray<>();
+ assertNull(UserRestrictionsUtils.mergeAll(restrictions));
+
+ restrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+ restrictions.put(1, newRestrictions(UserManager.DISALLOW_USB_FILE_TRANSFER));
+ restrictions.put(2, newRestrictions(UserManager.DISALLOW_APPS_CONTROL));
+
+ Bundle result = UserRestrictionsUtils.mergeAll(restrictions);
+ assertRestrictions(
+ newRestrictions(
+ UserManager.DISALLOW_ADJUST_VOLUME,
+ UserManager.DISALLOW_USB_FILE_TRANSFER,
+ UserManager.DISALLOW_APPS_CONTROL),
+ result);
+ }
+
+ public void testMoveRestriction() {
+ SparseArray<Bundle> localRestrictions = new SparseArray<>();
+ SparseArray<Bundle> globalRestrictions = new SparseArray<>();
+
+ // User 0 has only local restrictions, nothing should change.
+ localRestrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+ // User 1 has a local restriction to be moved to global and some global already. Local
+ // restrictions should be removed for this user.
+ localRestrictions.put(1, newRestrictions(UserManager.ENSURE_VERIFY_APPS));
+ globalRestrictions.put(1, newRestrictions(UserManager.DISALLOW_ADD_USER));
+ // User 2 has a local restriction to be moved and one to leave local.
+ localRestrictions.put(2, newRestrictions(
+ UserManager.ENSURE_VERIFY_APPS,
+ UserManager.DISALLOW_CONFIG_VPN));
+
+ UserRestrictionsUtils.moveRestriction(
+ UserManager.ENSURE_VERIFY_APPS, localRestrictions, globalRestrictions);
+
+ // Check user 0.
+ assertRestrictions(
+ newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME),
+ localRestrictions.get(0));
+ assertNull(globalRestrictions.get(0));
+
+ // Check user 1.
+ assertNull(localRestrictions.get(1));
+ assertRestrictions(
+ newRestrictions(UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_ADD_USER),
+ globalRestrictions.get(1));
+
+ // Check user 2.
+ assertRestrictions(
+ newRestrictions(UserManager.DISALLOW_CONFIG_VPN),
+ localRestrictions.get(2));
+ assertRestrictions(
+ newRestrictions(UserManager.ENSURE_VERIFY_APPS),
+ globalRestrictions.get(2));
}
public void testAreEqual() {
@@ -172,33 +288,33 @@
assertFalse(UserRestrictionsUtils.areEqual(
null,
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
+ newRestrictions("a"),
null));
assertTrue(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a"),
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a"),
- DpmTestUtils.newRestrictions("a", "b")));
+ newRestrictions("a"),
+ newRestrictions("a", "b")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("a", "b"),
- DpmTestUtils.newRestrictions("a")));
+ newRestrictions("a", "b"),
+ newRestrictions("a")));
assertFalse(UserRestrictionsUtils.areEqual(
- DpmTestUtils.newRestrictions("b", "a"),
- DpmTestUtils.newRestrictions("a", "a")));
+ newRestrictions("b", "a"),
+ newRestrictions("a", "a")));
// Make sure false restrictions are handled correctly.
- final Bundle a = DpmTestUtils.newRestrictions("a");
+ final Bundle a = newRestrictions("a");
a.putBoolean("b", true);
- final Bundle b = DpmTestUtils.newRestrictions("a");
+ final Bundle b = newRestrictions("a");
b.putBoolean("b", false);
assertFalse(UserRestrictionsUtils.areEqual(a, b));