blob: 0f1569e96861cdddae4a6761dffa07e13e55f93c [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 android.app.Activity;
import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.usage.NetworkStatsManager;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Point;
import android.net.ConnectivityManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.RemoteException;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
/** An activity (to be run as a foreground process) which performs one of a number of actions. */
public class StatsdCtsForegroundActivity extends Activity {
private static final String TAG = StatsdCtsForegroundActivity.class.getSimpleName();
public static final String KEY_ACTION = "action";
public static final String ACTION_CRASH = "action.crash";
public static final String ACTION_NATIVE_CRASH = "action.native_crash";
public static final String ACTION_END_IMMEDIATELY = "action.end_immediately";
public static final String ACTION_SLEEP_WHILE_TOP = "action.sleep_top";
public static final String ACTION_LONG_SLEEP_WHILE_TOP = "action.long_sleep_top";
public static final String ACTION_SHOW_APPLICATION_OVERLAY = "action.show_application_overlay";
public static final String ACTION_SHOW_NOTIFICATION = "action.show_notification";
public static final String ACTION_CREATE_CHANNEL_GROUP = "action.create_channel_group";
public static final String ACTION_POLL_NETWORK_STATS = "action.poll_network_stats";
public static final String ACTION_LMK = "action.lmk";
public static final String ACTION_DRAIN_POWER = "action.drain_power";
public static final int SLEEP_OF_ACTION_SLEEP_WHILE_TOP = 2_000;
public static final int SLEEP_OF_ACTION_SHOW_APPLICATION_OVERLAY = 2_000;
public static final int LONG_SLEEP_WHILE_TOP = 60_000;
static {
System.loadLibrary("crashhelper");
}
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
Intent intent = this.getIntent();
if (intent == null) {
Log.e(TAG, "Intent was null.");
finish();
}
String action = intent.getStringExtra(KEY_ACTION);
Log.i(TAG, "Starting " + action + " from foreground activity.");
switch (action) {
case ACTION_END_IMMEDIATELY:
finish();
break;
case ACTION_CRASH:
doCrash();
break;
case ACTION_NATIVE_CRASH:
doNativeCrash();
break;
case ACTION_SLEEP_WHILE_TOP:
doSleepWhileTop(SLEEP_OF_ACTION_SLEEP_WHILE_TOP);
break;
case ACTION_LONG_SLEEP_WHILE_TOP:
doSleepWhileTop(LONG_SLEEP_WHILE_TOP);
break;
case ACTION_SHOW_APPLICATION_OVERLAY:
doShowApplicationOverlay();
break;
case ACTION_SHOW_NOTIFICATION:
doShowNotification();
break;
case ACTION_CREATE_CHANNEL_GROUP:
doCreateChannelGroup();
break;
case ACTION_POLL_NETWORK_STATS:
doPollNetworkStats();
break;
case ACTION_LMK:
new Thread(MemoryHogger::allocate).start();
break;
case ACTION_DRAIN_POWER:
doBusyWork();
break;
default:
Log.e(TAG, "Intent had invalid action " + action);
finish();
}
}
/** Does nothing, but asynchronously. */
private void doSleepWhileTop(int sleepTime) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
AtomTests.sleep(sleepTime);
return null;
}
@Override
protected void onPostExecute(Void nothing) {
reportFullyDrawn();
finish();
}
}.execute();
}
private void doShowApplicationOverlay() {
// Adapted from BatteryStatsBgVsFgActions.java.
final WindowManager wm = getSystemService(WindowManager.class);
Point size = new Point();
wm.getDefaultDisplay().getSize(size);
WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
wmlp.width = size.x / 4;
wmlp.height = size.y / 4;
wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
wmlp.setTitle(getPackageName());
ViewGroup.LayoutParams vglp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
View v = new View(this);
v.setBackgroundColor(Color.GREEN);
v.setLayoutParams(vglp);
wm.addView(v, wmlp);
// The overlay continues long after the finish. The following is just to end the activity.
AtomTests.sleep(SLEEP_OF_ACTION_SHOW_APPLICATION_OVERLAY);
finish();
}
private void doShowNotification() {
final int notificationId = R.layout.activity_main;
final String notificationChannelId = "StatsdCtsChannel";
NotificationManager nm = getSystemService(NotificationManager.class);
NotificationChannel channel = new NotificationChannel(notificationChannelId, "Statsd Cts",
NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("Statsd Cts Channel");
nm.createNotificationChannel(channel);
nm.notify(
notificationId,
new Notification.Builder(this, notificationChannelId)
.setSmallIcon(android.R.drawable.stat_notify_chat)
.setContentTitle("StatsdCts")
.setContentText("StatsdCts")
.build());
nm.cancel(notificationId);
finish();
}
private void doCreateChannelGroup() {
NotificationManager nm = getSystemService(NotificationManager.class);
NotificationChannelGroup channelGroup = new NotificationChannelGroup("StatsdCtsGroup",
"Statsd Cts Group");
channelGroup.setDescription("StatsdCtsGroup Description");
nm.createNotificationChannelGroup(channelGroup);
finish();
}
// Trigger force poll on NetworkStatsService to make sure the service get most updated network
// stats from lower layer on subsequent verifications.
private void doPollNetworkStats() {
final NetworkStatsManager nsm =
(NetworkStatsManager) getSystemService(Context.NETWORK_STATS_SERVICE);
// While the flag of force polling is the only important thing needed when making binder
// call to service, the type, parameters and returned result of the query here do not
// matter.
try {
nsm.setPollForce(true);
nsm.querySummaryForUser(ConnectivityManager.TYPE_WIFI, null, Long.MIN_VALUE,
Long.MAX_VALUE);
} catch (RemoteException e) {
Log.e(TAG, "doPollNetworkStats failed with " + e);
} finally {
finish();
}
}
@SuppressWarnings("ConstantOverflow")
private void doCrash() {
Log.e(TAG, "About to crash the app with 1/0 " + (long) 1 / 0);
}
private void doNativeCrash() {
Log.e(TAG, "About to segfault the app");
segfault();
}
private void doBusyWork() {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
// Put a heavy load on the CPU
double sum = 0;
for (double t = 0; t < Double.MAX_VALUE; t += 1) {
sum += Math.sin(t);
}
Log.d(TAG, "Completed summing sines: " + sum);
return null;
}
@Override
protected void onPostExecute(Void nothing) {
finish();
}
}.execute();
}
private native void segfault();
}