Merge "Add support for suspending battery charging"
This commit is contained in:
committed by
Android (Google) Code Review
commit
63c6d3982d
@@ -50,6 +50,7 @@
|
||||
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
|
||||
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
|
||||
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
|
||||
<uses-permission android:name="android.permission.DEVICE_POWER"/>
|
||||
<uses-permission android:name="android.permission.DOWNLOAD_CACHE_NON_PURGEABLE" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.internal.os;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.BatteryManager;
|
||||
import android.os.Build;
|
||||
import android.os.ConditionVariable;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.compatibility.common.util.SystemUtil;
|
||||
|
||||
import com.google.android.collect.Sets;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class BatteryInputSuspendTest {
|
||||
|
||||
public static final Set<String> SUPPORTED_DEVICES = Sets.newArraySet(
|
||||
"blueline",
|
||||
"crosshatch",
|
||||
"coral"
|
||||
);
|
||||
|
||||
private ChargerStateMonitor mChargerStateMonitor;
|
||||
|
||||
@Before
|
||||
public void verifyCharging() {
|
||||
if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mChargerStateMonitor = new ChargerStateMonitor();
|
||||
|
||||
assertTrue("Device must be connected to USB", mChargerStateMonitor.isCharging());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuspendInput() {
|
||||
if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SystemUtil.runShellCommand("dumpsys battery suspend_input");
|
||||
|
||||
mChargerStateMonitor.waitForChargerState(/* isPluggedIn */false);
|
||||
}
|
||||
|
||||
@After
|
||||
public void reenableCharging() {
|
||||
if (!SUPPORTED_DEVICES.contains(Build.DEVICE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mChargerStateMonitor.reset();
|
||||
|
||||
SystemUtil.runShellCommand("dumpsys battery reset");
|
||||
|
||||
mChargerStateMonitor.waitForChargerState(/* isPluggedIn */true);
|
||||
}
|
||||
|
||||
private static class ChargerStateMonitor {
|
||||
private final Intent mBatteryMonitor;
|
||||
private final ConditionVariable mReady = new ConditionVariable();
|
||||
private boolean mExpectedChargingState;
|
||||
|
||||
ChargerStateMonitor() {
|
||||
Context context = InstrumentationRegistry.getInstrumentation().getContext();
|
||||
mBatteryMonitor = context.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (isCharging(intent) == mExpectedChargingState) {
|
||||
mReady.open();
|
||||
}
|
||||
}
|
||||
}, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
|
||||
}
|
||||
|
||||
public boolean isCharging() {
|
||||
return isCharging(mBatteryMonitor);
|
||||
}
|
||||
|
||||
private boolean isCharging(Intent batteryMonitor) {
|
||||
return batteryMonitor.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1) != 0;
|
||||
}
|
||||
|
||||
void waitForChargerState(boolean isPluggedIn) {
|
||||
mExpectedChargingState = isPluggedIn;
|
||||
|
||||
boolean charging = isCharging();
|
||||
if (charging == mExpectedChargingState) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean success = mReady.block(100000);
|
||||
assertTrue("Timed out waiting for charging state to change", success);
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mReady.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@ import android.os.BatteryManagerInternal;
|
||||
import android.os.BatteryProperty;
|
||||
import android.os.BatteryStats;
|
||||
import android.os.Binder;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.DropBoxManager;
|
||||
import android.os.FileUtils;
|
||||
@@ -59,6 +60,7 @@ import android.os.UEventObserver;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.service.battery.BatteryServiceDumpProto;
|
||||
import android.sysprop.PowerProperties;
|
||||
import android.util.EventLog;
|
||||
import android.util.MutableInt;
|
||||
import android.util.Slog;
|
||||
@@ -182,6 +184,7 @@ public final class BatteryService extends SystemService {
|
||||
private int mChargeStartLevel;
|
||||
|
||||
private boolean mUpdatesStopped;
|
||||
private boolean mBatteryInputSuspended;
|
||||
|
||||
private Led mLed;
|
||||
|
||||
@@ -234,6 +237,8 @@ public final class BatteryService extends SystemService {
|
||||
invalidChargerObserver.startObserving(
|
||||
"DEVPATH=/devices/virtual/switch/invalid_charger");
|
||||
}
|
||||
|
||||
mBatteryInputSuspended = PowerProperties.battery_input_suspended().orElse(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -876,6 +881,10 @@ public final class BatteryService extends SystemService {
|
||||
pw.println(" reset [-f]");
|
||||
pw.println(" Unfreeze battery state, returning to current hardware values.");
|
||||
pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
|
||||
if (Build.IS_DEBUGGABLE) {
|
||||
pw.println(" disable_charge");
|
||||
pw.println(" Suspend charging even if plugged in. ");
|
||||
}
|
||||
}
|
||||
|
||||
static final int OPTION_FORCE_UPDATE = 1<<0;
|
||||
@@ -997,6 +1006,20 @@ public final class BatteryService extends SystemService {
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
if (mBatteryInputSuspended) {
|
||||
PowerProperties.battery_input_suspended(false);
|
||||
mBatteryInputSuspended = false;
|
||||
}
|
||||
} break;
|
||||
case "suspend_input": {
|
||||
if (!Build.IS_DEBUGGABLE) {
|
||||
throw new SecurityException(
|
||||
"battery suspend_input is only supported on debuggable builds");
|
||||
}
|
||||
getContext().enforceCallingOrSelfPermission(
|
||||
android.Manifest.permission.DEVICE_POWER, null);
|
||||
PowerProperties.battery_input_suspended(true);
|
||||
mBatteryInputSuspended = true;
|
||||
} break;
|
||||
default:
|
||||
return shell.handleDefaultCommands(cmd);
|
||||
|
||||
Reference in New Issue
Block a user