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

Commit e77ef626 authored by Benjamin Schwartz's avatar Benjamin Schwartz Committed by Automerger Merge Worker
Browse files

Merge "stats: Pull power stats atoms from PowerStats service" into sc-dev am: 00e8383c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13431425

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I6545056a9851e72420b247696ad1773f6557d175
parents 86268e37 00e8383c
Loading
Loading
Loading
Loading
+23 −3
Original line number Diff line number Diff line
@@ -69,6 +69,8 @@ public class PowerStatsService extends SystemService {
    private BatteryTrigger mBatteryTrigger;
    @Nullable
    private TimerTrigger mTimerTrigger;
    @Nullable
    private StatsPullAtomCallbackImpl mPullAtomCallback;

    @VisibleForTesting
    static class Injector {
@@ -119,6 +121,11 @@ public class PowerStatsService extends SystemService {
        TimerTrigger createTimerTrigger(Context context, PowerStatsLogger powerStatsLogger) {
            return new TimerTrigger(context, powerStatsLogger, true /* trigger enabled */);
        }

        StatsPullAtomCallbackImpl createStatsPullerImpl(Context context,
                IPowerStatsHALWrapper powerStatsHALWrapper) {
            return new StatsPullAtomCallbackImpl(context, powerStatsHALWrapper);
        }
    }

    private final class BinderService extends Binder {
@@ -156,8 +163,10 @@ public class PowerStatsService extends SystemService {

    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_BOOT_COMPLETED) {
            onSystemServiceReady();
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            onSystemServicesReady();
        } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
            onBootCompleted();
        }
    }

@@ -170,7 +179,18 @@ public class PowerStatsService extends SystemService {
        publishBinderService(Context.POWER_STATS_SERVICE, new BinderService());
    }

    private void onSystemServiceReady() {
    private void onSystemServicesReady() {
        if (getPowerStatsHal().isInitialized()) {
            if (DEBUG) Slog.d(TAG, "Starting PowerStatsService statsd pullers");

            // Only start statsd pullers if initialization is successful.
            mPullAtomCallback = mInjector.createStatsPullerImpl(mContext, getPowerStatsHal());
        } else {
            Slog.e(TAG, "Failed to start PowerStatsService statsd pullers");
        }
    }

    private void onBootCompleted() {
        if (getPowerStatsHal().isInitialized()) {
            if (DEBUG) Slog.d(TAG, "Starting PowerStatsService loggers");

+152 −0
Original line number Diff line number Diff line
/*
 * 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.server.powerstats;

import android.app.StatsManager;
import android.content.Context;
import android.hardware.power.stats.Channel;
import android.hardware.power.stats.EnergyMeasurement;
import android.hardware.power.stats.PowerEntity;
import android.hardware.power.stats.State;
import android.hardware.power.stats.StateResidency;
import android.hardware.power.stats.StateResidencyResult;
import android.util.StatsEvent;

import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.powerstats.PowerStatsHALWrapper.IPowerStatsHALWrapper;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * StatsPullAtomCallbackImpl is responsible implementing the stats pullers for
 * SUBSYSTEM_SLEEP_STATE and ON_DEVICE_POWER_MEASUREMENT statsd atoms.
 */
public class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback {
    private Context mContext;
    private IPowerStatsHALWrapper mPowerStatsHALWrapper;
    private Map<Integer, Channel> mChannels = new HashMap();
    private Map<Integer, String> mEntityNames = new HashMap();
    private Map<Integer, Map<Integer, String>> mStateNames = new HashMap();;

    @Override
    public int onPullAtom(int atomTag, List<StatsEvent> data) {
        switch (atomTag) {
            case FrameworkStatsLog.SUBSYSTEM_SLEEP_STATE:
                return pullSubsystemSleepState(atomTag, data);
            case FrameworkStatsLog.ON_DEVICE_POWER_MEASUREMENT:
                return pullOnDevicePowerMeasurement(atomTag, data);
            default:
                throw new UnsupportedOperationException("Unknown tagId=" + atomTag);
        }
    }

    private void initPullOnDevicePowerMeasurement() {
        Channel[] channels = mPowerStatsHALWrapper.getEnergyMeterInfo();
        if (channels == null) {
            return;
        }

        for (int i = 0; i < channels.length; i++) {
            final Channel channel = channels[i];
            mChannels.put(channel.id, channel);
        }
    }

    private int pullOnDevicePowerMeasurement(int atomTag, List<StatsEvent> events) {
        EnergyMeasurement[] energyMeasurements = mPowerStatsHALWrapper.readEnergyMeters(new int[0]);
        if (energyMeasurements == null) {
            return StatsManager.PULL_SKIP;
        }

        for (int i = 0; i < energyMeasurements.length; i++) {
            // Only report energy measurements that have been accumulated since boot
            final EnergyMeasurement energyMeasurement = energyMeasurements[i];
            if (energyMeasurement.durationMs == energyMeasurement.timestampMs) {
                events.add(FrameworkStatsLog.buildStatsEvent(
                        atomTag,
                        mChannels.get(energyMeasurement.id).subsystem,
                        mChannels.get(energyMeasurement.id).name,
                        energyMeasurement.durationMs,
                        energyMeasurement.energyUWs));
            }
        }

        return StatsManager.PULL_SUCCESS;
    }

    private void initSubsystemSleepState() {
        PowerEntity[] entities = mPowerStatsHALWrapper.getPowerEntityInfo();
        if (entities == null) {
            return;
        }

        for (int i = 0; i < entities.length; i++) {
            final PowerEntity entity = entities[i];
            Map<Integer, String> states = new HashMap();
            for (int j = 0; j < entity.states.length; j++) {
                final State state = entity.states[j];
                states.put(state.id, state.name);
            }

            mEntityNames.put(entity.id, entity.name);
            mStateNames.put(entity.id, states);
        }
    }

    private int pullSubsystemSleepState(int atomTag, List<StatsEvent> events) {
        StateResidencyResult[] results =  mPowerStatsHALWrapper.getStateResidency(new int[0]);
        if (results == null) {
            return StatsManager.PULL_SKIP;
        }
        for (int i = 0; i < results.length; i++) {
            final StateResidencyResult result = results[i];
            for (int j = 0; j < result.stateResidencyData.length; j++) {
                final StateResidency stateResidency = result.stateResidencyData[j];
                events.add(FrameworkStatsLog.buildStatsEvent(
                        atomTag,
                        mEntityNames.get(result.id),
                        mStateNames.get(result.id).get(stateResidency.id),
                        stateResidency.totalStateEntryCount,
                        stateResidency.totalTimeInStateMs));
            }
        }

        return StatsManager.PULL_SUCCESS;
    }

    public StatsPullAtomCallbackImpl(Context context, IPowerStatsHALWrapper powerStatsHALWrapper) {
        mContext = context;
        mPowerStatsHALWrapper = powerStatsHALWrapper;
        initPullOnDevicePowerMeasurement();
        initSubsystemSleepState();

        StatsManager manager = mContext.getSystemService(StatsManager.class);
        manager.setPullAtomCallback(
                FrameworkStatsLog.SUBSYSTEM_SLEEP_STATE,
                null, // use default PullAtomMetadata values
                ConcurrentUtils.DIRECT_EXECUTOR,
                this);
        manager.setPullAtomCallback(
                FrameworkStatsLog.ON_DEVICE_POWER_MEASUREMENT,
                null, // use default PullAtomMetadata values
                ConcurrentUtils.DIRECT_EXECUTOR,
                this);
    }
}
+0 −3
Original line number Diff line number Diff line
@@ -407,8 +407,6 @@ public class StatsPullAtomService extends SystemService {
        mContext = context;
    }

    private native void nativeInit();

    /**
     * Use of this StatsPullAtomCallbackImpl means we avoid one class per tagId, which we would
     * get if we used lambdas.
@@ -681,7 +679,6 @@ public class StatsPullAtomService extends SystemService {
        super.onBootPhase(phase);
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            BackgroundThread.getHandler().post(() -> {
                nativeInit();
                initializePullersState();
                registerPullers();
                registerEventListeners();
+1 −3
Original line number Diff line number Diff line
@@ -25,8 +25,6 @@ cc_library_static {
        "gnss/GnssMeasurement.cpp",
        "gnss/GnssMeasurementCallback.cpp",
        "gnss/Utils.cpp",
        "stats/PowerStatsPuller.cpp",
        "stats/SubsystemSleepStatePuller.cpp",
        "com_android_server_adb_AdbDebuggingManager.cpp",
        "com_android_server_am_BatteryStatsService.cpp",
        "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
@@ -45,7 +43,6 @@ cc_library_static {
        "com_android_server_SerialService.cpp",
        "com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
        "com_android_server_soundtrigger_middleware_ExternalCaptureStateTracker.cpp",
        "com_android_server_stats_pull_StatsPullAtomService.cpp",
        "com_android_server_storage_AppFuseBridge.cpp",
        "com_android_server_SystemServer.cpp",
        "com_android_server_tv_TvUinputBridge.cpp",
@@ -152,6 +149,7 @@ cc_defaults {
        "android.hardware.power@1.1",
        "android.hardware.power-cpp",
        "android.hardware.power.stats@1.0",
        "android.hardware.power.stats-ndk_platform",
        "android.hardware.thermal@1.0",
        "android.hardware.tv.input@1.0",
        "android.hardware.vibrator-unstable-cpp",
+0 −71
Original line number Diff line number Diff line
/*
 * 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.
 */

#define LOG_TAG "StatsPullAtomService"

#include <jni.h>
#include <log/log.h>
#include <nativehelper/JNIHelp.h>
#include <stats_event.h>
#include <stats_pull_atom_callback.h>
#include <statslog.h>

#include "stats/PowerStatsPuller.h"
#include "stats/SubsystemSleepStatePuller.h"

namespace android {

static server::stats::PowerStatsPuller gPowerStatsPuller;
static server::stats::SubsystemSleepStatePuller gSubsystemSleepStatePuller;

static AStatsManager_PullAtomCallbackReturn onDevicePowerMeasurementCallback(int32_t atom_tag,
                                                                             AStatsEventList* data,
                                                                             void* cookie) {
    return gPowerStatsPuller.Pull(atom_tag, data);
}

static AStatsManager_PullAtomCallbackReturn subsystemSleepStateCallback(int32_t atom_tag,
                                                                        AStatsEventList* data,
                                                                        void* cookie) {
    return gSubsystemSleepStatePuller.Pull(atom_tag, data);
}

static void nativeInit(JNIEnv* env, jobject javaObject) {
    // on device power measurement
    gPowerStatsPuller = server::stats::PowerStatsPuller();
    AStatsManager_setPullAtomCallback(android::util::ON_DEVICE_POWER_MEASUREMENT,
                                      /* metadata= */ nullptr, onDevicePowerMeasurementCallback,
                                      /* cookie= */ nullptr);

    // subsystem sleep state
    gSubsystemSleepStatePuller = server::stats::SubsystemSleepStatePuller();
    AStatsManager_setPullAtomCallback(android::util::SUBSYSTEM_SLEEP_STATE,
                                      /* metadata= */ nullptr, subsystemSleepStateCallback,
                                      /* cookie= */ nullptr);
}

static const JNINativeMethod sMethods[] = {{"nativeInit", "()V", (void*)nativeInit}};

int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env) {
    int res = jniRegisterNativeMethods(env, "com/android/server/stats/pull/StatsPullAtomService",
                                       sMethods, NELEM(sMethods));
    if (res < 0) {
        ALOGE("failed to register native methods");
    }
    return res;
}

} // namespace android
Loading