blob: 401a2e7395d0acfa6b8fff70c95952098df62044 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.cts.deviceowner;
import static com.google.common.truth.Truth.assertWithMessage;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.os.Process;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import com.android.cts.devicepolicy.TestCertificates;
import com.google.common.collect.Range;
import java.io.ByteArrayInputStream;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AdminActionBookkeepingTest extends BaseDeviceOwnerTest {
private static final String TAG = AdminActionBookkeepingTest.class.getSimpleName();
private static final int NOTIFICATION_TIMEOUT_MS = 5 * 60_000; // 5 minutes
@Override
protected void tearDown() throws Exception {
mDevicePolicyManager.setSecurityLoggingEnabled(getWho(), false);
mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), false);
mDevicePolicyManager.uninstallCaCert(getWho(), TestCertificates.TEST_CA.getBytes());
super.tearDown();
}
/**
* Test: Retrieving security logs should update the corresponding timestamp.
*/
public void testRetrieveSecurityLogs() throws Exception {
Log.i(TAG, "testRetrieveSecurityLogs()");
sleep(1);
final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
mDevicePolicyManager.setSecurityLoggingEnabled(getWho(), true);
long timeBefore = System.currentTimeMillis();
mDevicePolicyManager.retrieveSecurityLogs(getWho());
long timeAfter = System.currentTimeMillis();
final long firstTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
assertTimeStamps(timeBefore, previousTimestamp, firstTimestamp, timeAfter);
sleep(2);
timeBefore = System.currentTimeMillis();
final boolean preBootSecurityLogsRetrieved =
mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho()) != null;
timeAfter = System.currentTimeMillis();
final long secondTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
if (preBootSecurityLogsRetrieved) {
// If the device supports pre-boot security logs, verify that retrieving them updates
// the timestamp.
assertTimeStamps(timeBefore, firstTimestamp, secondTimestamp, timeAfter);
} else {
// If the device does not support pre-boot security logs, verify that the attempt to
// retrieve them does not update the timestamp.
assertWithMessage("timestamp when device does not support pre-boot security logs")
.that(firstTimestamp).isEqualTo(secondTimestamp);
}
}
/**
* Test: Requesting a bug report should update the corresponding timestamp.
*/
public void testRequestBugreport() throws Exception {
Log.i(TAG, "testRequestBugreport()");
// This test leaves a notification which will block future tests that request bug reports
// to fix this - we dismiss the bug report before returning
CountDownLatch notificationDismissedLatch = initTestRequestBugreport();
sleep(1);
final long previousTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
final long timeBefore = System.currentTimeMillis();
mDevicePolicyManager.requestBugreport(getWho());
final long timeAfter = System.currentTimeMillis();
final long newTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
assertTimeStamps(timeBefore, previousTimestamp, newTimestamp, timeAfter);
cleanupTestRequestBugreport(notificationDismissedLatch);
}
private CountDownLatch initTestRequestBugreport() {
CountDownLatch notificationDismissedLatch = new CountDownLatch(1);
NotificationListener.getInstance().addListener((sbt) -> {
Log.i(TAG, "Received notification: " + sbt);
// The notification we are looking for is the one which confirms the bug report is
// ready and asks for consent to send it
if (sbt.getPackageName().equals("android") &&
sbt.getTag().equals("DevicePolicyManager") &&
sbt.getNotification().actions != null) {
try {
// The first action is to decline
sbt.getNotification().actions[0].actionIntent.send();
notificationDismissedLatch.countDown();
} catch (PendingIntent.CanceledException e) {
String msg = "Could not dismiss bug report notification";
Log.e(TAG, msg, e);
fail(msg);
}
}
});
return notificationDismissedLatch;
}
private void cleanupTestRequestBugreport(CountDownLatch notificationDismissedLatch)
throws Exception {
Log.d(TAG, "Waiting " + NOTIFICATION_TIMEOUT_MS + "ms for bugreport notification");
if (!notificationDismissedLatch.await(NOTIFICATION_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
String msg = "Didn't receive bugreport notification in " + NOTIFICATION_TIMEOUT_MS
+ " ms";
Log.e(TAG, msg);
fail(msg);
}
NotificationListener.getInstance().clearListeners();
}
/**
* Test: Retrieving network logs should update the corresponding timestamp.
*/
public void testGetLastNetworkLogRetrievalTime() throws Exception {
Log.i(TAG, "testGetLastNetworkLogRetrievalTime()");
sleep(1);
final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
mDevicePolicyManager.setNetworkLoggingEnabled(getWho(), true);
long timeBefore = System.currentTimeMillis();
mDevicePolicyManager.retrieveNetworkLogs(getWho(), 0 /* batchToken */);
long timeAfter = System.currentTimeMillis();
final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
assertTimeStamps(timeBefore, previousTimestamp, newTimestamp, timeAfter);
}
/**
* Test: The Device Owner should be able to set and retrieve the name of the organization
* managing the device.
*/
public void testDeviceOwnerOrganizationName() throws Exception {
Log.i(TAG, "testDeviceOwnerOrganizationName()");
mDevicePolicyManager.setOrganizationName(getWho(), null);
assertWithMessage("dpm.getDeviceOwnerOrganizationName()")
.that(mDevicePolicyManager.getDeviceOwnerOrganizationName()).isNull();
mDevicePolicyManager.setOrganizationName(getWho(), "organization");
assertWithMessage("dpm.getDeviceOwnerOrganizationName()")
.that(mDevicePolicyManager.getDeviceOwnerOrganizationName())
.isEqualTo("organization");
mDevicePolicyManager.setOrganizationName(getWho(), null);
assertWithMessage("dpm.getDeviceOwnerOrganizationName()")
.that(mDevicePolicyManager.getDeviceOwnerOrganizationName()).isNull();
}
/**
* Test: When a Device Owner is set, isDeviceManaged() should return true.
*/
public void testIsDeviceManaged() throws Exception {
Log.i(TAG, "testIsDeviceManaged()");
assertWithMessage("dpm.isDeviceManaged()").that(mDevicePolicyManager.isDeviceManaged())
.isTrue();
}
/**
* Test: It should be recored whether the Device Owner or the user set the current IME.
*/
public void testIsDefaultInputMethodSet() throws Exception {
Log.i(TAG, "testIsDefaultInputMethodSet()");
final String setting = Settings.Secure.DEFAULT_INPUT_METHOD;
final String ime = getSecureSettings(setting);
setSecureSettings(setting, "com.test.1");
sleep(500);
assertWithMessage("dpm.isCurrentInputMethodSetByOwner()")
.that(mDevicePolicyManager.isCurrentInputMethodSetByOwner()).isFalse();
mDevicePolicyManager.setSecureSetting(getWho(), setting, "com.test.2");
sleep(500);
assertWithMessage("%s.isCurrentInputMethodSetByOwner()", mDevicePolicyManager)
.that(mDevicePolicyManager.isCurrentInputMethodSetByOwner()).isTrue();
setSecureSettings(setting, ime);
sleep(500);
assertWithMessage("%s.isCurrentInputMethodSetByOwner()", mDevicePolicyManager)
.that(mDevicePolicyManager.isCurrentInputMethodSetByOwner()).isFalse();
}
/**
* Test: It should be recored whether the Device Owner or the user installed a CA cert.
*/
public void testGetPolicyInstalledCaCerts() throws Exception {
Log.i(TAG, "testGetPolicyInstalledCaCerts()");
final byte[] rawCert = TestCertificates.TEST_CA.getBytes();
final Certificate cert = CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(rawCert));
// Install a CA cert.
KeyStore keyStore = KeyStore.getInstance("AndroidCAStore");
keyStore.load(null, null);
assertWithMessage("keystore.getCertificateAlias()").that(keyStore.getCertificateAlias(cert))
.isNull();
assertWithMessage("dpm.installCaCert()")
.that(mDevicePolicyManager.installCaCert(getWho(), rawCert)).isTrue();
final String alias = keyStore.getCertificateAlias(cert);
assertWithMessage("keystore.getCertificateAlias()").that(alias).isNotNull();
// Verify that the CA cert was marked as installed by the Device Owner.
verifyOwnerInstalledStatus(alias, true);
// Uninstall the CA cert.
mDevicePolicyManager.uninstallCaCert(getWho(), rawCert);
// Verify that the CA cert is no longer marked as installed by the Device Owner.
verifyOwnerInstalledStatus(alias, false);
}
private void verifyOwnerInstalledStatus(String alias, boolean expectOwnerInstalled) {
final UserHandle user = Process.myUserHandle();
final List<String> ownerInstalledCerts =
mDevicePolicyManager.getOwnerInstalledCaCerts(user);
assertWithMessage("dpm.getOwnerInstalledCaCerts(%s)", user).that(ownerInstalledCerts)
.isNotNull();
if (expectOwnerInstalled) {
assertWithMessage("dpm.getOwnerInstalledCaCerts(%s)", user).that(ownerInstalledCerts)
.contains(alias);
} else {
assertWithMessage("dpm.getOwnerInstalledCaCerts(%s)", user).that(ownerInstalledCerts)
.doesNotContain(alias);
}
}
private void sleep(int durationMs) throws InterruptedException {
Log.v(TAG, "Sleeping for " + durationMs + " ms on thread " + Thread.currentThread());
Thread.sleep(durationMs);
Log.v(TAG, "Woke up");
}
private void assertTimeStamps(long before, long timeStamp1, long timeStamp2, long after) {
assertWithMessage("first and second timestamp order").that(timeStamp2)
.isGreaterThan(timeStamp1);
assertWithMessage("second timestamp range").that(timeStamp2)
.isIn(Range.closed(before, after));
}
private void setSecureSettings(String name, String value) {
final ContentResolver resolver = getContext().getContentResolver();
Log.d(TAG, "Setting '" + name + "'='" + value + "' on user " + getContext().getUserId());
Settings.Secure.putString(resolver, name , value);
Log.v(TAG, "Set");
}
private String getSecureSettings(String name) {
final ContentResolver resolver = getContext().getContentResolver();
String value = Settings.Secure.getString(resolver, name);
Log.d(TAG, "Got '" + name + "' for user " + getContext().getUserId() + ": " + value);
return value;
}
}