packages/modules/Scheduling/service/java/com/android/server/scheduling/RebootReadinessShellCommand...

225 lines
9.5 KiB
Java

/*
* Copyright (C) 2021 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.scheduling;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.provider.DeviceConfig;
import android.scheduling.RebootReadinessManager;
import com.android.modules.utils.BasicShellCommandHandler;
import java.io.PrintWriter;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
/**
* Interprets and executes "adb shell cmd reboot_readiness [args]".
*/
class RebootReadinessShellCommand extends BasicShellCommandHandler {
final RebootReadinessManagerService mService;
final Context mContext;
// How long to perform reboot readiness checks for.
private long mTimeoutSecs = TimeUnit.MINUTES.toSeconds(5);
// When true, blocking app uids or subsystem identifiers may be listed.
private boolean mListBlocking;
// DeviceConfig properties
private static final String PROPERTY_ACTIVE_POLLING_INTERVAL_MS = "active_polling_interval_ms";
private static final String PROPERTY_INTERACTIVITY_THRESHOLD_MS = "interactivity_threshold_ms";
private static final String PROPERTY_DISABLE_INTERACTIVITY_CHECK =
"disable_interactivity_check";
private static final String PROPERTY_DISABLE_APP_ACTIVITY_CHECK = "disable_app_activity_check";
private static final String PROPERTY_DISABLE_SUBSYSTEMS_CHECK = "disable_subsystems_check";
RebootReadinessShellCommand(RebootReadinessManagerService service, Context context) {
mService = service;
mContext = context;
}
@Override
public int onCommand(String cmd) {
if (cmd == null) {
return handleDefaultCommands(cmd);
}
switch (cmd) {
case "check-interactivity-state":
runCheckInteractivityState();
break;
case "check-subsystems-state":
runCheckSubsystemsState();
break;
case "check-app-activity-state":
runCheckAppActivityState();
break;
case "start-readiness-checks":
runStartReadinessChecks();
break;
default:
return handleDefaultCommands(cmd);
}
return 1;
}
private void handleOptions() {
String arg;
while ((arg = getNextArg()) != null) {
switch (arg) {
case "--timeout-secs":
mTimeoutSecs = Long.parseLong(getNextArgRequired());
break;
case "--list-blocking":
mListBlocking = true;
break;
case "--polling-interval-ms":
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_REBOOT_READINESS,
PROPERTY_ACTIVE_POLLING_INTERVAL_MS, getNextArgRequired(), false);
break;
case "--interactivity-threshold-ms":
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_REBOOT_READINESS,
PROPERTY_INTERACTIVITY_THRESHOLD_MS, getNextArgRequired(), false);
break;
case "--disable-app-activity-check":
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_REBOOT_READINESS,
PROPERTY_DISABLE_APP_ACTIVITY_CHECK, "true", false);
break;
case "--disable-subsystems-check":
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_REBOOT_READINESS,
PROPERTY_DISABLE_SUBSYSTEMS_CHECK, "true", false);
break;
case "disable-interactivity-check":
case "--disable-interactivity-check":
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_REBOOT_READINESS,
PROPERTY_DISABLE_INTERACTIVITY_CHECK, "true", false);
break;
default:
break;
}
}
// Allow DeviceConfig values to propagate.
try {
Thread.sleep(1000);
} catch (Exception ignored) {
}
}
/**
* Registers for reboot readiness state change broadcasts for a certain amount of time. If
* the state changes, it will be printed along with a timestamp.
*/
private void runStartReadinessChecks() {
handleOptions();
IntentFilter filter = new IntentFilter(RebootReadinessManager.ACTION_REBOOT_READY);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
LocalDateTime dt = LocalDateTime.now();
getOutPrintWriter().println("State changed to " + intent.getBooleanExtra(
RebootReadinessManager.EXTRA_IS_READY_TO_REBOOT, false)
+ " at time: " + dt.format(DateTimeFormatter.ISO_LOCAL_TIME));
getOutPrintWriter().flush();
}
};
try {
mContext.registerReceiver(receiver, filter);
getOutPrintWriter().println("Initial state: " + mService.isReadyToReboot());
getOutPrintWriter().flush();
mService.markRebootPending(mContext.getPackageName());
while (mTimeoutSecs-- > 0) {
Thread.sleep(1000);
}
} catch (Exception ignored) {
} finally {
mService.cancelPendingReboot(mContext.getPackageName());
}
}
/**
* Checks the device interactivity state. Prints false if the reboot is blocked by device
* interactivity, true otherwise.
*/
private void runCheckInteractivityState() {
handleOptions();
getOutPrintWriter().println("Interactivity state: " + mService.checkDeviceInteractivity());
}
/**
* Checks the subsystem reboot readiness. Prints false if the reboot is blocked by any
* subsystems, true otherwise. If --list-blocking is passed, the culprit subsystems
* will be printed.
*/
private void runCheckSubsystemsState() {
handleOptions();
getOutPrintWriter().println("Subsystem state: " + mService.checkSystemComponentsState());
if (mListBlocking) {
mService.writeBlockingSubsystems(getOutPrintWriter());
}
}
/**
* Checks the app activity reboot readiness. Prints false if the reboot is blocked by any
* app uids, true otherwise. If --list-blocking is passed, the culprit packages will be printed.
*/
private void runCheckAppActivityState() {
handleOptions();
getOutPrintWriter().println("App activity state: " + mService.checkBackgroundAppActivity());
if (mListBlocking) {
mService.writeBlockingUids(getOutPrintWriter());
}
}
@Override
public void onHelp() {
final PrintWriter pw = getOutPrintWriter();
pw.println("Reboot readiness (reboot_readiness) commands: ");
pw.println(" help: ");
pw.println(" Prints this help text.");
pw.println(" check-interactivity-state:");
pw.println(" Checks interactivity state.");
pw.println(" check-app-activity-state [--list-blocking]:");
pw.println(" Checks background app activity state. If --list-blocking is passed, a");
pw.println(" list of blocking uids will be printed if any exist.");
pw.println(" check-subsystems-state [--list-blocking]:");
pw.println(" Checks subsystems state. If --list-blocking is passed, a list of");
pw.println(" blocking subsystems will be printed if any exist.");
pw.println(" start-readiness-checks [--timeout-secs <TIMEOUT-SECS>]:");
pw.println(" Performs reboot readiness checks for either 5 minutes, or the");
pw.println(" number of seconds declared by TIMEOUT-SECS. Prints the new reboot");
pw.println(" readiness state along with a timestamp whenever the state changes.");
pw.println();
pw.println("Additional flags that may be passed:");
pw.println(" --polling-interval-ms <POLLING-INTERVAL-MS>:");
pw.println(" How frequently the reboot readiness state is polled, in milliseconds.");
pw.println(" --interactivity-threshold-ms <INTERACTIVITY-THRESHOLD-MS>:");
pw.println(" How long the device must not have been interacted with before");
pw.println(" being deemed ready to reboot.");
pw.println(" --disable-interactivity-check / disable-interactivity-check:");
pw.println(" Disable interactivity checks.");
pw.println(" --disable-subsystems-check:");
pw.println(" Disable subsystems checks:");
pw.println(" --disable-app-activity-check:");
pw.println(" Disable app activity checks.");
}
}