Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 774a7e61 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Adding uid attribution mechanism for kernel wakeups

BatteryStats currently only stores the reason it receives from the
suspend control service. Starting with this change, batterystats will
now try to attribute these wakeups in more detail.

IRQ style wakeups where there has been an IRQ from a device get a
well structured reason string from the kernel. CpuWakeupStats will parse
it to get irq devices and then use irq_device_map xml to map the wakeup
to possible pre-defined subsystems that may have caused it.

Different parts of the system can use these subsystems to report any
associated activity (not to be confused with the class
android.app.Activity) tha could have caused a wakeup. CpuWakeupStats
will then attempt to associate this information with any wakeup that
may have occurred due to an IRQ from the relevant device.

This change defines the "Alarm" subsystem, and relies on the device
overlay to map this subsystem to the rtc device that ultimately enables
waking up the CPU when needed to process a wakeup alarm. Whenever there
is a batch of wakeup alarms that is dispatched, alarm manager notifies
batterystats (and hence cpuwakeupstats) of this "activity", which will
then try to associate it with any temporally proximal wakeups that have
happened due to the rtc device.

Currently, the information supported is only the uids that have
requested or initiated the activity from the subsystem that should be
blamed for the wakeup. But this can be extended to include more enum
style codes to represent other information.

Test: atest FrameworksServicesTests:IrqDeviceMapTest
Test: atest FrameworksServicesTests:CpuWakeupStatsTest

Bug: 249370357
Bug: 195684213
Change-Id: Idfbba82e9c007b5c9f15b9fd785b9a96cb202572
parent b65e3341
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -87,6 +87,7 @@ import android.content.pm.PackageManagerInternal;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.BatteryManager;
import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
@@ -116,6 +117,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.EventLog;
import android.util.IndentingPrintWriter;
import android.util.IntArray;
import android.util.Log;
import android.util.LongArrayQueue;
import android.util.Pair;
@@ -249,6 +251,7 @@ public class AlarmManagerService extends SystemService {
    private ActivityManagerInternal mActivityManagerInternal;
    private final EconomyManagerInternal mEconomyManagerInternal;
    private PackageManagerInternal mPackageManagerInternal;
    private BatteryStatsInternal mBatteryStatsInternal;
    private RoleManager mRoleManager;
    private volatile PermissionManagerServiceInternal mLocalPermissionManager;

@@ -2113,6 +2116,8 @@ public class AlarmManagerService extends SystemService {
                    LocalServices.getService(AppStandbyInternal.class);
            appStandbyInternal.addListener(new AppStandbyTracker());

            mBatteryStatsInternal = LocalServices.getService(BatteryStatsInternal.class);

            mRoleManager = getContext().getSystemService(RoleManager.class);

            mMetricsHelper.registerPuller(() -> mAlarmStore);
@@ -4783,8 +4788,12 @@ public class AlarmManagerService extends SystemService {
                            }
                            final ArraySet<Pair<String, Integer>> triggerPackages =
                                    new ArraySet<>();
                            final IntArray wakeupUids = new IntArray();
                            for (int i = 0; i < triggerList.size(); i++) {
                                final Alarm a = triggerList.get(i);
                                if (a.wakeup) {
                                    wakeupUids.add(a.uid);
                                }
                                if (mConstants.USE_TARE_POLICY) {
                                    if (!isExemptFromTare(a)) {
                                        triggerPackages.add(Pair.create(
@@ -4796,6 +4805,11 @@ public class AlarmManagerService extends SystemService {
                                            a.sourcePackage, UserHandle.getUserId(a.creatorUid)));
                                }
                            }
                            if (wakeupUids.size() > 0 && mBatteryStatsInternal != null) {
                                mBatteryStatsInternal.noteCpuWakingActivity(
                                        BatteryStatsInternal.CPU_WAKEUP_SUBSYSTEM_ALARM, nowELAPSED,
                                        wakeupUids.toArray());
                            }
                            deliverAlarmsLocked(triggerList, nowELAPSED);
                            mTemporaryQuotaReserve.cleanUpExpiredQuotas(nowELAPSED);
                            if (mConstants.USE_TARE_POLICY) {
+1 −1
Original line number Diff line number Diff line
@@ -2017,7 +2017,7 @@ public abstract class BatteryStats {
        public static final int EVENT_PACKAGE_INSTALLED = 0x000b;
        // Event for a package being uninstalled.
        public static final int EVENT_PACKAGE_UNINSTALLED = 0x000c;
        // Event for a package being uninstalled.
        // Event for an alarm being sent out to an app.
        public static final int EVENT_ALARM = 0x000d;
        // Record that we have decided we need to collect new stats data.
        public static final int EVENT_COLLECT_EXTERNAL_STATS = 0x000e;
+1 −0
Original line number Diff line number Diff line
@@ -1626,6 +1626,7 @@
  <java-symbol type="xml" name="password_kbd_symbols_shift" />
  <java-symbol type="xml" name="power_profile" />
  <java-symbol type="xml" name="power_profile_test" />
  <java-symbol type="xml" name="irq_device_map" />
  <java-symbol type="xml" name="sms_short_codes" />
  <java-symbol type="xml" name="audio_assets" />
  <java-symbol type="xml" name="global_keys" />
+50 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
**
** Copyright 2022, 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.
*/
-->
<irq-device-map>
  <!--  This file maps devices (chips) that can send IRQs to the CPU (and bring it out of sleep) to
        logical subsystems in userspace code. Since each Android device has its own uniquely
        designed chipset, this mapping is expected to be empty by default and should be overridden
        by device specific configs.
        This mapping helps the system to meaningfully attribute CPU wakeups to logical work that
        happened on the device. The devices are referred to by their names as defined in the kernel.
        Currently defined subsystems are:
        - Alarm: Use this to denote wakeup alarms requested by apps via the AlarmManager API.

        The overlay should use tags <device> and <subsystem> to describe this mapping in the
        following way:

        <irq-device-map>
            <device name="device_name_1">
                <subsystem>Subsystem1</subsystem>
                <subsystem>Subsystem2</subsystem>
                :
                :
            </device>
            <device name="device_name_2">
                :
            </device>
            :
        </irq-device-map>

        The tag <device> should have a "name" attribute specifying the kernel name of the device.
        Each <device> tag can then enclose multiple <subsystem> tags. Each <subsystem> tag should
        enclose the name of the logical subsystems (one of the ones defined above) as text.
        Undefined subsystem names will be ignored by the framework.
  -->
</irq-device-map>
 No newline at end of file
+29 −2
Original line number Diff line number Diff line
@@ -16,12 +16,18 @@

package android.os;

import android.annotation.IntDef;
import android.annotation.NonNull;

import com.android.internal.os.BinderCallsStats;
import com.android.server.power.stats.SystemServerCpuThreadReader.SystemServiceCpuThreadTimes;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Collection;
import java.util.List;


/**
 * Battery stats local system service interface. This is used to pass internal data out of
 * BatteryStatsImpl, as well as make unchecked calls into BatteryStatsImpl.
@@ -29,6 +35,19 @@ import java.util.List;
 * @hide Only for use within Android OS.
 */
public abstract class BatteryStatsInternal {

    public static final int CPU_WAKEUP_SUBSYSTEM_UNKNOWN = -1;
    public static final int CPU_WAKEUP_SUBSYSTEM_ALARM = 1;

    /** @hide */
    @IntDef(prefix = {"CPU_WAKEUP_SUBSYSTEM_"}, value = {
            CPU_WAKEUP_SUBSYSTEM_UNKNOWN,
            CPU_WAKEUP_SUBSYSTEM_ALARM,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface CpuWakeupSubsystem {
    }

    /**
     * Returns the wifi interfaces.
     */
@@ -56,6 +75,7 @@ public abstract class BatteryStatsInternal {
    /**
     * Inform battery stats how many deferred jobs existed when the app got launched and how
     * long ago was the last job execution for the app.
     *
     * @param uid         the uid of the app.
     * @param numDeferred number of deferred jobs.
     * @param sinceLast   how long in millis has it been since a job was run
@@ -72,4 +92,11 @@ public abstract class BatteryStatsInternal {
     * Informs battery stats of native thread IDs of threads taking incoming binder calls.
     */
    public abstract void noteBinderThreadNativeIds(int[] binderThreadNativeTids);

    /**
     * Reports any activity that could potentially have caused the CPU to wake up.
     * Accepts a timestamp to allow the reporter to report it before or after the event.
     */
    public abstract void noteCpuWakingActivity(@CpuWakeupSubsystem int subsystem,
            long elapsedMillis, @NonNull int... uids);
}
Loading