blob: ef24a7afbe09a02dfd71547d7ce3dd8d71cecbcc [file] [log] [blame]
/*
* Copyright (C) 2017 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.server.cts.device.statsdatom;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.google.common.truth.Truth.assertWithMessage;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlarmManager;
import android.app.AppOpsManager;
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.location.GnssStatus;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.media.MediaPlayer;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.cts.util.CtsNetUtils;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.StatsEvent;
import android.util.StatsLog;
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.ShellIdentityUtils;
import org.junit.Assert;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
public class AtomTests {
private static final String TAG = AtomTests.class.getSimpleName();
private static final String MY_PACKAGE_NAME = "com.android.server.cts.device.statsdatom";
private static final Map<String, Integer> APP_OPS_ENUM_MAP = new ArrayMap<>();
static {
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_COARSE_LOCATION, 0);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_FINE_LOCATION, 1);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GPS, 2);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_VIBRATE, 3);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CONTACTS, 4);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CONTACTS, 5);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CALL_LOG, 6);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CALL_LOG, 7);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CALENDAR, 8);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CALENDAR, 9);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WIFI_SCAN, 10);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_POST_NOTIFICATION, 11);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_NEIGHBORING_CELLS, 12);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CALL_PHONE, 13);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_SMS, 14);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_SMS, 15);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_SMS, 16);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_EMERGENCY_BROADCAST, 17);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_MMS, 18);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECEIVE_WAP_PUSH, 19);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SEND_SMS, 20);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_ICC_SMS, 21);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_ICC_SMS, 22);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_SETTINGS, 23);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, 24);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS, 25);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CAMERA, 26);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_AUDIO, 27);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PLAY_AUDIO, 28);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CLIPBOARD, 29);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_CLIPBOARD, 30);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TAKE_MEDIA_BUTTONS, 31);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TAKE_AUDIO_FOCUS, 32);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_MASTER_VOLUME, 33);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_VOICE_VOLUME, 34);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_RING_VOLUME, 35);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_MEDIA_VOLUME, 36);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_ALARM_VOLUME, 37);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_NOTIFICATION_VOLUME, 38);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_BLUETOOTH_VOLUME, 39);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WAKE_LOCK, 40);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MONITOR_LOCATION, 41);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION, 42);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GET_USAGE_STATS, 43);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MUTE_MICROPHONE, 44);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TOAST_WINDOW, 45);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PROJECT_MEDIA, 46);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVATE_VPN, 47);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_WALLPAPER, 48);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ASSIST_STRUCTURE, 49);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ASSIST_SCREENSHOT, 50);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_PHONE_STATE, 51);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ADD_VOICEMAIL, 52);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_SIP, 53);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS, 54);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_FINGERPRINT, 55);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BODY_SENSORS, 56);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_CELL_BROADCASTS, 57);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MOCK_LOCATION, 58);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE, 59);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE, 60);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_TURN_SCREEN_ON, 61);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_GET_ACCOUNTS, 62);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RUN_IN_BACKGROUND, 63);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUDIO_ACCESSIBILITY_VOLUME, 64);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, 65);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES, 66);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PICTURE_IN_PICTURE, 67);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_INSTANT_APP_START_FOREGROUND, 68);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ANSWER_PHONE_CALLS, 69);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RUN_ANY_IN_BACKGROUND, 70);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_CHANGE_WIFI_STATE, 71);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_REQUEST_DELETE_PACKAGES, 72);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE, 73);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCEPT_HANDOVER, 74);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS, 75);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_START_FOREGROUND, 76);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BLUETOOTH_SCAN, 77);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_BIOMETRIC, 78);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVITY_RECOGNITION, 79);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS, 80);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_AUDIO, 81);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_AUDIO, 82);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_VIDEO, 83);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_VIDEO, 84);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_MEDIA_IMAGES, 85);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_WRITE_MEDIA_IMAGES, 86);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_LEGACY_STORAGE, 87);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY, 88);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, 89);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACCESS_MEDIA_LOCATION, 90);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_QUERY_ALL_PACKAGES, 91);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE, 92);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES, 93);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, 94);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_LOADER_USAGE_STATS, 95);
// Op 96 was deprecated/removed
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, 97);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_AUTO_REVOKE_MANAGED_BY_INSTALLER, 98);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_NO_ISOLATED_STORAGE, 99);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PHONE_CALL_MICROPHONE, 100);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_PHONE_CALL_CAMERA, 101);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD, 102);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_ONGOING_CALLS, 103);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_CREDENTIALS, 104);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER, 105);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_AUDIO_OUTPUT, 106);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_SCHEDULE_EXACT_ALARM, 107);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_FINE_LOCATION_SOURCE, 108);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_COARSE_LOCATION_SOURCE, 109);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_MANAGE_MEDIA, 110);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BLUETOOTH_CONNECT, 111);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_UWB_RANGING, 112);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ACTIVITY_RECOGNITION_SOURCE, 113);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_BLUETOOTH_ADVERTISE, 114);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_RECORD_INCOMING_PHONE_AUDIO, 115);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_NEARBY_WIFI_DEVICES, 116);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE, 117);
APP_OPS_ENUM_MAP.put(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER, 118);
}
@Test
// Start the isolated service, which logs an AppBreadcrumbReported atom, and then exit.
public void testIsolatedProcessService() throws Exception {
Context context = InstrumentationRegistry.getContext();
Intent intent = new Intent(context, IsolatedProcessService.class);
context.startService(intent);
sleep(2_000);
context.stopService(intent);
}
@Test
public void testAudioState() {
// TODO: This should surely be getTargetContext(), here and everywhere, but test first.
Context context = InstrumentationRegistry.getContext();
MediaPlayer mediaPlayer = MediaPlayer.create(context, R.raw.good);
mediaPlayer.start();
sleep(2_000);
mediaPlayer.stop();
}
@Test
public void testBleScanOpportunistic() {
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_OPPORTUNISTIC).build();
performBleScan(scanSettings, null,false);
}
@Test
public void testBleScanUnoptimized() {
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
performBleScan(scanSettings, null, false);
}
@Test
public void testBleScanResult() {
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
ScanFilter.Builder scanFilter = new ScanFilter.Builder();
performBleScan(scanSettings, Arrays.asList(scanFilter.build()), true);
}
@Test
public void testBleScanInterrupted() throws Exception {
performBleAction((bluetoothAdapter, bleScanner) -> {
ScanSettings scanSettings = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
Log.v(TAG, "called onScanResult");
}
@Override
public void onScanFailed(int errorCode) {
Log.v(TAG, "called onScanFailed");
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
Log.v(TAG, "called onBatchScanResults");
}
};
int uid = Process.myUid();
int whatAtomId = 9_999;
// Get the current setting for bluetooth background scanning.
// Set to 0 if the setting is not found or an error occurs.
int initialBleScanGlobalSetting = Settings.Global.getInt(
InstrumentationRegistry.getTargetContext().getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
// Turn off bluetooth background scanning.
Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, 0);
// Change state to State.ON.
bleScanner.startScan(null, scanSettings, scanCallback);
sleep(6_000);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
bluetoothAdapter.disable();
sleep(6_000);
// Trigger State.RESET so that new state is State.OFF.
if (!bluetoothAdapter.enable()) {
Log.e(TAG, "Could not enable bluetooth to trigger state reset");
return;
}
sleep(6_000); // Wait for Bluetooth to fully turn on.
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
writeSliceByBleScanStateChangedAtom(whatAtomId, uid, false, false, false);
// Set bluetooth background scanning to original setting.
Settings.Global.putInt(InstrumentationRegistry.getTargetContext().getContentResolver(),
Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE, initialBleScanGlobalSetting);
});
}
private static void writeSliceByBleScanStateChangedAtom(int atomId, int firstUid,
boolean field2, boolean field3,
boolean field4) {
final StatsEvent.Builder builder = StatsEvent.newBuilder()
.setAtomId(atomId)
.writeAttributionChain(new int[] {firstUid}, new String[] {"tag1"})
.writeBoolean(field2)
.writeBoolean(field3)
.writeBoolean(field4)
.usePooledBuffer();
StatsLog.write(builder.build());
}
/**
* Set up BluetoothLeScanner and perform the action in the callback.
* Restore Bluetooth to original state afterwards.
**/
private static void performBleAction(BiConsumer<BluetoothAdapter, BluetoothLeScanner> actions) {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (bluetoothAdapter == null) {
Log.e(TAG, "Device does not support Bluetooth");
return;
}
boolean bluetoothEnabledByTest = false;
if (!bluetoothAdapter.isEnabled()) {
if (!bluetoothAdapter.enable()) {
Log.e(TAG, "Bluetooth is not enabled");
return;
}
sleep(2_000); // Wait for Bluetooth to fully turn on.
bluetoothEnabledByTest = true;
}
BluetoothLeScanner bleScanner = bluetoothAdapter.getBluetoothLeScanner();
if (bleScanner == null) {
Log.e(TAG, "Cannot access BLE scanner");
return;
}
actions.accept(bluetoothAdapter, bleScanner);
// Restore adapter state
if (bluetoothEnabledByTest) {
bluetoothAdapter.disable();
}
}
private static void performBleScan(ScanSettings scanSettings, List<ScanFilter> scanFilters, boolean waitForResult) {
performBleAction((bluetoothAdapter, bleScanner) -> {
CountDownLatch resultsLatch = new CountDownLatch(1);
ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
Log.v(TAG, "called onScanResult");
resultsLatch.countDown();
}
@Override
public void onScanFailed(int errorCode) {
Log.v(TAG, "called onScanFailed");
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
Log.v(TAG, "called onBatchScanResults");
resultsLatch.countDown();
}
};
bleScanner.startScan(scanFilters, scanSettings, scanCallback);
if (waitForResult) {
waitForReceiver(InstrumentationRegistry.getContext(), 59_000, resultsLatch, null);
} else {
sleep(2_000);
}
bleScanner.stopScan(scanCallback);
});
}
@Test
public void testCameraState() throws Exception {
Context context = InstrumentationRegistry.getContext();
CameraManager cam = context.getSystemService(CameraManager.class);
String[] cameraIds = cam.getCameraIdList();
if (cameraIds.length == 0) {
Log.e(TAG, "No camera found on device");
return;
}
CountDownLatch latch = new CountDownLatch(1);
final CameraDevice.StateCallback cb = new CameraDevice.StateCallback() {
@Override
public void onOpened(CameraDevice cd) {
Log.i(TAG, "CameraDevice " + cd.getId() + " opened");
sleep(2_000);
cd.close();
}
@Override
public void onClosed(CameraDevice cd) {
latch.countDown();
Log.i(TAG, "CameraDevice " + cd.getId() + " closed");
}
@Override
public void onDisconnected(CameraDevice cd) {
Log.w(TAG, "CameraDevice " + cd.getId() + " disconnected");
}
@Override
public void onError(CameraDevice cd, int error) {
Log.e(TAG, "CameraDevice " + cd.getId() + "had error " + error);
}
};
HandlerThread handlerThread = new HandlerThread("br_handler_thread");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
cam.openCamera(cameraIds[0], cb, handler);
waitForReceiver(context, 10_000, latch, null);
}
@Test
public void testFlashlight() throws Exception {
Context context = InstrumentationRegistry.getContext();
CameraManager cam = context.getSystemService(CameraManager.class);
String[] cameraIds = cam.getCameraIdList();
boolean foundFlash = false;
for (int i = 0; i < cameraIds.length; i++) {
String id = cameraIds[i];
if(cam.getCameraCharacteristics(id).get(CameraCharacteristics.FLASH_INFO_AVAILABLE)) {
cam.setTorchMode(id, true);
sleep(500);
cam.setTorchMode(id, false);
foundFlash = true;
break;
}
}
if(!foundFlash) {
Log.e(TAG, "No flashlight found on device");
}
}
@Test
public void testForegroundService() throws Exception {
Context context = InstrumentationRegistry.getContext();
// The service goes into foreground and exits shortly
Intent intent = new Intent(context, StatsdCtsForegroundService.class);
context.startService(intent);
sleep(500);
context.stopService(intent);
}
@Test
public void testForegroundServiceAccessAppOp() throws Exception {
Context context = InstrumentationRegistry.getContext();
Intent fgsIntent = new Intent(context, StatsdCtsForegroundService.class);
AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
// No foreground service session
noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION);
sleep(500);
// Foreground service session 1
context.startService(fgsIntent);
while (!checkIfServiceRunning(context, StatsdCtsForegroundService.class.getName())) {
sleep(50);
}
noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
noteAppOp(appOpsManager, AppOpsManager.OPSTR_FINE_LOCATION);
noteAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
startAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO);
noteAppOp(appOpsManager, AppOpsManager.OPSTR_RECORD_AUDIO);
startAppOp(appOpsManager, AppOpsManager.OPSTR_CAMERA);
sleep(500);
context.stopService(fgsIntent);
// No foreground service session
noteAppOp(appOpsManager, AppOpsManager.OPSTR_COARSE_LOCATION);
sleep(500);
// TODO(b/149098800): Start fgs a second time and log OPSTR_CAMERA again
}
@Test
public void testAppOps() throws Exception {
Context context = InstrumentationRegistry.getContext();
AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
String[] opsList = appOpsManager.getOpStrs();
for (int i = 0; i < opsList.length; i++) {
String op = opsList[i];
if (TextUtils.isEmpty(op)) {
// Operation removed/deprecated
continue;
}
int noteCount = APP_OPS_ENUM_MAP.getOrDefault(op, opsList.length) + 1;
for (int j = 0; j < noteCount; j++) {
try {
noteAppOp(appOpsManager, opsList[i]);
} catch (SecurityException e) {}
}
}
}
private void noteAppOp(AppOpsManager aom, String opStr) {
aom.noteOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null, "statsdTest");
}
private void startAppOp(AppOpsManager aom, String opStr) {
aom.startOp(opStr, android.os.Process.myUid(), MY_PACKAGE_NAME, null, "statsdTest");
}
/** Check if service is running. */
public boolean checkIfServiceRunning(Context context, String serviceName) {
ActivityManager manager = context.getSystemService(ActivityManager.class);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceName.equals(service.service.getClassName()) && service.foreground) {
return true;
}
}
return false;
}
@Test
public void testGpsScan() {
Context context = InstrumentationRegistry.getContext();
final LocationManager locManager = context.getSystemService(LocationManager.class);
if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.e(TAG, "GPS provider is not enabled");
return;
}
CountDownLatch latch = new CountDownLatch(1);
final LocationListener locListener = new LocationListener() {
public void onLocationChanged(Location location) {
Log.v(TAG, "onLocationChanged: location has been obtained");
}
public void onProviderDisabled(String provider) {
Log.w(TAG, "onProviderDisabled " + provider);
}
public void onProviderEnabled(String provider) {
Log.w(TAG, "onProviderEnabled " + provider);
}
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.w(TAG, "onStatusChanged " + provider + " " + status);
}
};
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
Looper.prepare();
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 990, 0,
locListener);
sleep(1_000);
locManager.removeUpdates(locListener);
latch.countDown();
return null;
}
}.execute();
waitForReceiver(context, 59_000, latch, null);
}
@Test
public void testGpsStatus() {
Context context = InstrumentationRegistry.getContext();
final LocationManager locManager = context.getSystemService(LocationManager.class);
if (!locManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
Log.e(TAG, "GPS provider is not enabled");
return;
}
// Time out set to 85 seconds (5 seconds for sleep and a possible 85 seconds if TTFF takes
// max time which would be around 90 seconds.
// This is based on similar location cts test timeout values.
final int TIMEOUT_IN_MSEC = 85_000;
final int SLEEP_TIME_IN_MSEC = 5_000;
final CountDownLatch mLatchNetwork = new CountDownLatch(1);
final LocationListener locListener = location -> {
Log.v(TAG, "onLocationChanged: location has been obtained");
mLatchNetwork.countDown();
};
// fetch the networklocation first to make sure the ttff is not flaky
if (locManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
Log.i(TAG, "Request Network Location updates.");
locManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
0 /* minTime*/,
0 /* minDistance */,
locListener,
Looper.getMainLooper());
}
waitForReceiver(context, TIMEOUT_IN_MSEC, mLatchNetwork, null);
// TTFF could take up to 90 seconds, thus we need to wait till TTFF does occur if it does
// not occur in the first SLEEP_TIME_IN_MSEC
final CountDownLatch mLatchTtff = new CountDownLatch(1);
GnssStatus.Callback gnssStatusCallback = new GnssStatus.Callback() {
@Override
public void onStarted() {
Log.v(TAG, "Gnss Status Listener Started");
}
@Override
public void onStopped() {
Log.v(TAG, "Gnss Status Listener Stopped");
}
@Override
public void onFirstFix(int ttffMillis) {
Log.v(TAG, "Gnss Status Listener Received TTFF");
mLatchTtff.countDown();
}
@Override
public void onSatelliteStatusChanged(GnssStatus status) {
Log.v(TAG, "Gnss Status Listener Received Status Update");
}
};
boolean gnssStatusCallbackAdded = locManager.registerGnssStatusCallback(
gnssStatusCallback, new Handler(Looper.getMainLooper()));
if (!gnssStatusCallbackAdded) {
// Registration of GnssMeasurements listener has failed, this indicates a platform bug.
Log.e(TAG, "Failed to start gnss status callback");
}
locManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
0,
0 /* minDistance */,
locListener,
Looper.getMainLooper());
sleep(SLEEP_TIME_IN_MSEC);
waitForReceiver(context, TIMEOUT_IN_MSEC, mLatchTtff, null);
locManager.removeUpdates(locListener);
locManager.unregisterGnssStatusCallback(gnssStatusCallback);
}
@Test
public void testScreenBrightness() {
Context context = InstrumentationRegistry.getContext();
PowerManager pm = context.getSystemService(PowerManager.class);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK |
PowerManager.ACQUIRE_CAUSES_WAKEUP, "StatsdBrightnessTest");
wl.acquire();
sleep(500);
setScreenBrightness(47);
sleep(500);
setScreenBrightness(100);
sleep(500);
setScreenBrightness(140);
sleep(500);
wl.release();
}
@Test
public void testSyncState() throws Exception {
Context context = InstrumentationRegistry.getContext();
StatsdAuthenticator.removeAllAccounts(context);
AccountManager am = context.getSystemService(AccountManager.class);
CountDownLatch latch = StatsdSyncAdapter.resetCountDownLatch();
Account account = StatsdAuthenticator.getTestAccount();
StatsdAuthenticator.ensureTestAccount(context);
sleep(500);
// Just force set is syncable.
ContentResolver.setMasterSyncAutomatically(true);
sleep(500);
ContentResolver.setIsSyncable(account, StatsdProvider.AUTHORITY, 1);
// Wait for the first (automatic) sync to finish
waitForReceiver(context, 120_000, latch, null);
//Sleep for 500ms, since we assert each start/stop to be ~500ms apart.
sleep(500);
// Request and wait for the second sync to finish
latch = StatsdSyncAdapter.resetCountDownLatch();
StatsdSyncAdapter.requestSync(account);
waitForReceiver(context, 120_000, latch, null);
StatsdAuthenticator.removeAllAccounts(context);
}
@Test
public void testScheduledJob() throws Exception {
final ComponentName name = new ComponentName(MY_PACKAGE_NAME,
StatsdJobService.class.getName());
Context context = InstrumentationRegistry.getContext();
JobScheduler js = context.getSystemService(JobScheduler.class);
assertWithMessage("JobScheduler service not available").that(js).isNotNull();
JobInfo.Builder builder = new JobInfo.Builder(1, name);
builder.setOverrideDeadline(0);
JobInfo job = builder.build();
long startTime = System.currentTimeMillis();
CountDownLatch latch = StatsdJobService.resetCountDownLatch();
js.schedule(job);
waitForReceiver(context, 5_000, latch, null);
}
@Test
public void testVibratorState() {
Context context = InstrumentationRegistry.getContext();
Vibrator vib = context.getSystemService(Vibrator.class);
if (vib.hasVibrator()) {
vib.vibrate(VibrationEffect.createOneShot(
500 /* ms */, VibrationEffect.DEFAULT_AMPLITUDE));
}
// Sleep so that the app does not get killed.
sleep(1000);
}
@Test
public void testWakelockState() {
Context context = InstrumentationRegistry.getContext();
PowerManager pm = context.getSystemService(PowerManager.class);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"StatsdPartialWakelock");
wl.acquire();
sleep(500);
wl.release();
}
@Test
public void testSliceByWakelockState() {
int uid = Process.myUid();
int whatAtomId = 9_998;
int wakelockType = PowerManager.PARTIAL_WAKE_LOCK;
String tag = "StatsdPartialWakelock";
Context context = InstrumentationRegistry.getContext();
PowerManager pm = context.getSystemService(PowerManager.class);
PowerManager.WakeLock wl = pm.newWakeLock(wakelockType, tag);
wl.acquire();
sleep(500);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
wl.acquire();
sleep(500);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
wl.release();
sleep(500);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
wl.release();
sleep(500);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
writeSliceByWakelockStateChangedAtom(whatAtomId, uid, wakelockType, tag);
}
private static void writeSliceByWakelockStateChangedAtom(int atomId, int firstUid,
int field2, String field3) {
final StatsEvent.Builder builder = StatsEvent.newBuilder()
.setAtomId(atomId)
.writeAttributionChain(new int[] {firstUid}, new String[] {"tag1"})
.writeInt(field2)
.writeString(field3)
.usePooledBuffer();
StatsLog.write(builder.build());
}
@Test
public void testWakelockLoad() {
final int NUM_THREADS = 16;
CountDownLatch latch = new CountDownLatch(NUM_THREADS);
for (int i = 0; i < NUM_THREADS; i++) {
Thread t = new Thread(new WakelockLoadTestRunnable("StatsdPartialWakelock" + i, latch));
t.start();
}
waitForReceiver(null, 120_000, latch, null);
}
@Test
public void testWakeupAlarm() {
Context context = InstrumentationRegistry.getContext();
String name = "android.cts.statsdatom.testWakeupAlarm";
CountDownLatch onReceiveLatch = new CountDownLatch(1);
BroadcastReceiver receiver =
registerReceiver(context, onReceiveLatch, new IntentFilter(name));
AlarmManager manager = (AlarmManager) (context.getSystemService(AlarmManager.class));
PendingIntent pintent = PendingIntent.getBroadcast(context, 0, new Intent(name),
PendingIntent.FLAG_IMMUTABLE);
manager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + 2_000, pintent);
waitForReceiver(context, 10_000, onReceiveLatch, receiver);
}
@Test
public void testAlarmScheduled() {
Context context = InstrumentationRegistry.getContext();
String name = "android.cts.statsdatom.testAlarmScheduled";
final AlarmManager am = context.getSystemService(AlarmManager.class);
PendingIntent pi1 = PendingIntent.getBroadcast(context, 1, new Intent(name),
PendingIntent.FLAG_IMMUTABLE);
PendingIntent pi2 = PendingIntent.getBroadcast(context, 2, new Intent(name),
PendingIntent.FLAG_IMMUTABLE);
final long trigger1 = SystemClock.elapsedRealtime() + 5_000;
final long trigger2 = System.currentTimeMillis() + 5_200;
am.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, trigger1, pi1);
am.setWindow(AlarmManager.RTC, trigger2, 10_000, pi2);
}
@Test
public void testPendingAlarmInfo() {
Context context = InstrumentationRegistry.getContext();
final AlarmManager am = context.getSystemService(AlarmManager.class);
// Just schedule esoteric alarms whose counts can be verified in the pulled atom.
PendingIntent activity = PendingIntent.getActivity(context, 0,
new Intent("com.irrelevant.activity"), PendingIntent.FLAG_IMMUTABLE);
PendingIntent fgs1 = PendingIntent.getForegroundService(context, 1,
new Intent("com.irrelevant.fgs1"), PendingIntent.FLAG_IMMUTABLE);
PendingIntent fgs2 = PendingIntent.getForegroundService(context, 2,
new Intent("com.irrelevant.fgs2"), PendingIntent.FLAG_IMMUTABLE);
PendingIntent service = PendingIntent.getService(context, 0,
new Intent("com.irrelevant.service"), PendingIntent.FLAG_IMMUTABLE);
final long farTriggerRtc = System.currentTimeMillis() + 600_000;
final long farTriggerElapsed = SystemClock.elapsedRealtime() + 600_000;
final long neverTriggerElapsed = SystemClock.elapsedRealtime() + 10 * 365 * 86400 * 1000L;
am.set(AlarmManager.RTC_WAKEUP, farTriggerRtc, "testPendingAlarmInfo",
() -> Log.e(TAG, "Should not have fired"), null);
am.setAlarmClock(new AlarmManager.AlarmClockInfo(farTriggerRtc, activity), activity);
am.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, farTriggerElapsed, fgs1);
am.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, farTriggerElapsed, 60_000, fgs2);
am.setAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, neverTriggerElapsed, service);
}
@Test
public void testWifiLockHighPerf() {
Context context = InstrumentationRegistry.getContext();
WifiManager wm = context.getSystemService(WifiManager.class);
WifiManager.WifiLock lock =
wm.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "StatsdCTSWifiLock");
lock.acquire();
sleep(500);
lock.release();
}
@Test
public void testWifiLockLowLatency() {
Context context = InstrumentationRegistry.getContext();
WifiManager wm = context.getSystemService(WifiManager.class);
WifiManager.WifiLock lock =
wm.createWifiLock(WifiManager.WIFI_MODE_FULL_LOW_LATENCY, "StatsdCTSWifiLock");
lock.acquire();
sleep(500);
lock.release();
}
@Test
public void testWifiMulticastLock() {
Context context = InstrumentationRegistry.getContext();
WifiManager wm = context.getSystemService(WifiManager.class);
WifiManager.MulticastLock lock = wm.createMulticastLock("StatsdCTSMulticastLock");
lock.acquire();
sleep(500);
lock.release();
}
@Test
/** Does two wifi scans. */
// TODO: Copied this from BatterystatsValidation but we probably don't need to wait for results.
public void testWifiScan() {
Context context = InstrumentationRegistry.getContext();
IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
// Sometimes a scan was already running (from a different uid), so the first scan doesn't
// start when requested. Therefore, additionally wait for whatever scan is currently running
// to finish, then request a scan again - at least one of these two scans should be
// attributed to this app.
for (int i = 0; i < 2; i++) {
CountDownLatch onReceiveLatch = new CountDownLatch(1);
BroadcastReceiver receiver = registerReceiver(context, onReceiveLatch, intentFilter);
context.getSystemService(WifiManager.class).startScan();
waitForReceiver(context, 60_000, onReceiveLatch, receiver);
}
}
@Test
public void testWifiReconnect() throws Exception {
Context context = InstrumentationRegistry.getContext();
boolean wifiConnected = isWifiConnected(context);
Assert.assertTrue(
"Wifi is not connected. The test expects Wifi to be connected before the run",
wifiConnected);
wifiDisconnect(context);
sleep(500);
wifiReconnect(context);
sleep(500);
}
@Test
public void testSimpleCpu() {
long timestamp = System.currentTimeMillis();
for (int i = 0; i < 10000; i ++) {
timestamp += i;
}
Log.i(TAG, "The answer is " + timestamp);
}
@Test
public void testWriteRawTestAtom() throws Exception {
Context context = InstrumentationRegistry.getTargetContext();
ApplicationInfo appInfo = context.getPackageManager()
.getApplicationInfo(context.getPackageName(), 0);
int[] uids = {1234, appInfo.uid};
String[] tags = {"tag1", "tag2"};
byte[] experimentIds = {8, 1, 8, 2, 8, 3}; // Corresponds to 1, 2, 3.
StatsLogStatsdCts.write(StatsLogStatsdCts.TEST_ATOM_REPORTED, uids, tags, 42,
Long.MAX_VALUE, 3.14f, "This is a basic test!", false,
StatsLogStatsdCts.TEST_ATOM_REPORTED__STATE__ON, experimentIds);
// All nulls. Should get dropped since cts app is not in the attribution chain.
StatsLogStatsdCts.write(StatsLogStatsdCts.TEST_ATOM_REPORTED, null, null, 0, 0,
0f, null, false, StatsLogStatsdCts.TEST_ATOM_REPORTED__STATE__ON, null);
// Null tag in attribution chain.
int[] uids2 = {9999, appInfo.uid};
String[] tags2 = {"tag9999", null};
StatsLogStatsdCts.write(StatsLogStatsdCts.TEST_ATOM_REPORTED, uids2, tags2, 100,
Long.MIN_VALUE, -2.5f, "Test null uid", true,
StatsLogStatsdCts.TEST_ATOM_REPORTED__STATE__UNKNOWN, experimentIds);
// Non chained non-null
StatsLogStatsdCts.write_non_chained(StatsLogStatsdCts.TEST_ATOM_REPORTED,
appInfo.uid, "tag1", -256, -1234567890L, 42.01f, "Test non chained", true,
StatsLogStatsdCts.TEST_ATOM_REPORTED__STATE__OFF, experimentIds);
// Non chained all null
StatsLogStatsdCts.write_non_chained(StatsLogStatsdCts.TEST_ATOM_REPORTED, appInfo.uid, null,
0, 0, 0f, null, true, StatsLogStatsdCts.TEST_ATOM_REPORTED__STATE__OFF, null);
}
/**
* Bring up and generate some traffic on cellular data connection.
*/
@Test
public void testGenerateMobileTraffic() throws Exception {
final Context context = InstrumentationRegistry.getContext();
doGenerateNetworkTraffic(context, NetworkCapabilities.TRANSPORT_CELLULAR);
}
// Constants which are locally used by doGenerateNetworkTraffic.
private static final int NETWORK_TIMEOUT_MILLIS = 15000;
private static final String HTTPS_HOST_URL =
"https://connectivitycheck.gstatic.com/generate_204";
private void doGenerateNetworkTraffic(@NonNull Context context, int transport)
throws InterruptedException {
final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
final NetworkRequest request = new NetworkRequest.Builder().addCapability(
NetworkCapabilities.NET_CAPABILITY_INTERNET).addTransportType(transport).build();
final CtsNetUtils.TestNetworkCallback callback = new CtsNetUtils.TestNetworkCallback();
// Request network, and make http query when the network is available.
cm.requestNetwork(request, callback);
// If network is not available, throws IllegalStateException.
final Network network = callback.waitForAvailable();
if (network == null) {
throw new IllegalStateException("network with transport " + transport
+ " is not available.");
}
final long startTime = SystemClock.elapsedRealtime();
try {
exerciseRemoteHost(cm, network, new URL(HTTPS_HOST_URL));
Log.i(TAG, "exerciseRemoteHost successful in " + (SystemClock.elapsedRealtime()
- startTime) + " ms");
} catch (Exception e) {
Log.e(TAG, "exerciseRemoteHost failed in " + (SystemClock.elapsedRealtime()
- startTime) + " ms: " + e);
} finally {
cm.unregisterNetworkCallback(callback);
}
}
/**
* Generate traffic on specified network.
*/
private void exerciseRemoteHost(@NonNull ConnectivityManager cm, @NonNull Network network,
@NonNull URL url) throws Exception {
cm.bindProcessToNetwork(network);
HttpURLConnection urlc = null;
try {
urlc = (HttpURLConnection) network.openConnection(url);
urlc.setConnectTimeout(NETWORK_TIMEOUT_MILLIS);
urlc.setUseCaches(false);
urlc.connect();
} finally {
if (urlc != null) {
urlc.disconnect();
}
}
}
// ------- Helper methods
/** Puts the current thread to sleep. */
static void sleep(int millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted exception while sleeping", e);
}
}
/** Register receiver to determine when given action is complete. */
private static BroadcastReceiver registerReceiver(
Context ctx, CountDownLatch onReceiveLatch, IntentFilter intentFilter) {
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Received broadcast.");
onReceiveLatch.countDown();
}
};
// Run Broadcast receiver in a different thread since the main thread will wait.
HandlerThread handlerThread = new HandlerThread("br_handler_thread");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
ctx.registerReceiver(receiver, intentFilter, null, handler);
return receiver;
}
/**
* Uses the receiver to wait until the action is complete. ctx and receiver may be null if no
* receiver is needed to be unregistered.
*/
private static void waitForReceiver(Context ctx,
int maxWaitTimeMs, CountDownLatch latch, BroadcastReceiver receiver) {
try {
boolean didFinish = latch.await(maxWaitTimeMs, TimeUnit.MILLISECONDS);
if (didFinish) {
Log.v(TAG, "Finished performing action");
} else {
// This is not necessarily a problem. If we just want to make sure a count was
// recorded for the request, it doesn't matter if the action actually finished.
Log.w(TAG, "Did not finish in specified time.");
}
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted exception while awaiting action to finish", e);
}
if (ctx != null && receiver != null) {
ctx.unregisterReceiver(receiver);
}
}
private static void setScreenBrightness(int brightness) {
runShellCommand("settings put system screen_brightness " + brightness);
}
private static final int WIFI_CONNECT_TIMEOUT_MILLIS = 30_000;
public void wifiDisconnect(Context context) throws Exception {
WifiManager wifiManager = context.getSystemService(WifiManager.class);
ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.disconnect());
PollingCheck.check(
"Timed out waiting for Wifi to become disconnected",
WIFI_CONNECT_TIMEOUT_MILLIS,
() -> !isWifiConnected(context));
}
public void wifiReconnect(Context context) throws Exception {
WifiManager wifiManager = context.getSystemService(WifiManager.class);
ShellIdentityUtils.invokeWithShellPermissions(() -> wifiManager.reconnect());
PollingCheck.check(
"Timed out waiting for Wifi to become connected",
WIFI_CONNECT_TIMEOUT_MILLIS,
() -> isWifiConnected(context));
}
private boolean isWifiConnected(Context context) throws Exception {
ConnectivityManager connManager = context.getSystemService(ConnectivityManager.class);
if (connManager == null) {
return false;
}
Network[] networks = connManager.getAllNetworks();
for (Network network : networks) {
if (network == null) {
continue;
}
NetworkCapabilities caps = connManager.getNetworkCapabilities(network);
if (caps == null) {
continue;
}
if (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
return true;
}
}
return false;
}
@Test
public void testLoadingApks() throws Exception {
final Context context = InstrumentationRegistry.getContext();
final ApplicationInfo appInfo = context.getPackageManager()
.getApplicationInfo(context.getPackageName(), 0);
final String codePath = appInfo.sourceDir;
final String apkDir = codePath.substring(0, codePath.lastIndexOf('/'));
for (String apkName : new File(apkDir).list()) {
final String apkPath = apkDir + "/" + apkName;
if (new File(apkPath).isFile()) {
try {
Files.readAllBytes(Paths.get(apkPath));
} catch (IOException ignored) {
// Probably hitting pages that we are intentionally blocking
}
}
}
}
}