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

Commit c9e8b8a0 authored by mxyyiyi's avatar mxyyiyi
Browse files

Support Private Space in battery usage.

- Use database cache for single-user single-profile
- Reload battery usage info in other cases

Bug: 299032923
Test: manual
Change-Id: I5e524a094422639eedbf6e07eda498f3f72fccae
parent 470c27b8
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -556,9 +556,11 @@ public class BatteryChartPreferenceController extends AbstractPreferenceControll
                String.format(
                        "getBatterySinceLastFullChargeUsageData() size=%d time=%d/ms",
                        batteryHistoryMap.size(), (System.currentTimeMillis() - start)));

        final Map<Integer, Map<Integer, BatteryDiffData>> batteryUsageData =
                DataProcessor.getBatteryUsageData(context, batteryHistoryMap);
                DataProcessor.getBatteryUsageData(
                        context,
                        new UserIdsSeries(context, /* mainUserOnly= */ false),
                        batteryHistoryMap);
        if (batteryUsageData == null) {
            return null;
        }
+11 −5
Original line number Diff line number Diff line
@@ -84,12 +84,12 @@ public final class BatteryUsageDataLoader {
    }

    @VisibleForTesting
    static void loadAppUsageData(final Context context) {
    static void loadAppUsageData(final Context context, final UserIdsSeries userIdsSeries) {
        final long start = System.currentTimeMillis();
        final Map<Long, UsageEvents> appUsageEvents =
                sFakeAppUsageEventsSupplier != null
                        ? sFakeAppUsageEventsSupplier.get()
                        : DataProcessor.getAppUsageEvents(context);
                        : DataProcessor.getAppUsageEvents(context, userIdsSeries);
        if (appUsageEvents == null) {
            Log.w(TAG, "loadAppUsageData() returns null");
            return;
@@ -113,13 +113,15 @@ public final class BatteryUsageDataLoader {
        DatabaseUtils.sendAppUsageEventData(context, appUsageEventList);
    }

    private static void preprocessBatteryUsageSlots(final Context context) {
    private static void preprocessBatteryUsageSlots(
            final Context context, final UserIdsSeries userIdsSeries) {
        final long start = System.currentTimeMillis();
        final Handler handler = new Handler(Looper.getMainLooper());
        final BatteryLevelData batteryLevelData =
                DataProcessManager.getBatteryLevelData(
                        context,
                        handler,
                        userIdsSeries,
                        /* isFromPeriodJob= */ true,
                        batteryDiffDataMap -> {
                            DatabaseUtils.sendBatteryUsageSlotData(
@@ -162,8 +164,12 @@ public final class BatteryUsageDataLoader {
            loadBatteryStatsData(context, isFullChargeStart);
            if (!isFullChargeStart) {
                // No app usage data or battery diff data at this time.
                loadAppUsageData(context);
                preprocessBatteryUsageSlots(context);
                final UserIdsSeries userIdsSeries =
                        new UserIdsSeries(context, /* mainUserOnly= */ true);
                if (!userIdsSeries.isCurrentUserLocked()) {
                    loadAppUsageData(context, userIdsSeries);
                    preprocessBatteryUsageSlots(context, userIdsSeries);
                }
            }
            Log.d(
                    TAG,
+44 −59
Original line number Diff line number Diff line
@@ -21,8 +21,6 @@ import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.ArrayMap;
import android.util.Log;

@@ -30,7 +28,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.settings.Utils;

import java.util.ArrayList;
import java.util.Calendar;
@@ -82,7 +79,7 @@ public class DataProcessManager {
    private final long mLastFullChargeTimestamp;
    private final Context mContext;
    private final Handler mHandler;
    private final UserManager mUserManager;
    private final UserIdsSeries mUserIdsSeries;
    private final OnBatteryDiffDataMapLoadedListener mCallbackFunction;
    private final List<AppUsageEvent> mAppUsageEventList = new ArrayList<>();
    private final List<BatteryEvent> mBatteryEventList = new ArrayList<>();
@@ -123,6 +120,7 @@ public class DataProcessManager {
    DataProcessManager(
            Context context,
            Handler handler,
            final UserIdsSeries userIdsSeries,
            final long rawStartTimestamp,
            final long lastFullChargeTimestamp,
            @NonNull final OnBatteryDiffDataMapLoadedListener callbackFunction,
@@ -130,7 +128,7 @@ public class DataProcessManager {
            @NonNull final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
        mContext = context.getApplicationContext();
        mHandler = handler;
        mUserManager = mContext.getSystemService(UserManager.class);
        mUserIdsSeries = userIdsSeries;
        mRawStartTimestamp = rawStartTimestamp;
        mLastFullChargeTimestamp = lastFullChargeTimestamp;
        mCallbackFunction = callbackFunction;
@@ -142,10 +140,11 @@ public class DataProcessManager {
    DataProcessManager(
            Context context,
            Handler handler,
            final UserIdsSeries userIdsSeries,
            @NonNull final OnBatteryDiffDataMapLoadedListener callbackFunction) {
        mContext = context.getApplicationContext();
        mHandler = handler;
        mUserManager = mContext.getSystemService(UserManager.class);
        mUserIdsSeries = userIdsSeries;
        mCallbackFunction = callbackFunction;
        mRawStartTimestamp = 0L;
        mLastFullChargeTimestamp = 0L;
@@ -175,10 +174,18 @@ public class DataProcessManager {
                // Loads the latest app usage list from the service.
                loadCurrentAppUsageList();
                // Loads existing battery usage slots from database.
                if (mUserIdsSeries.isMainUserProfileOnly()) {
                    loadBatteryUsageSlotList();
                } else {
                    mIsBatteryUsageSlotLoaded = true;
                }
            }
            // Loads app usage list from database.
            if (mUserIdsSeries.isMainUserProfileOnly()) {
                loadDatabaseAppUsageList();
            } else {
                mIsDatabaseAppUsageLoaded = true;
            }
            // Loads the battery event list from database.
            loadPowerConnectionBatteryEventList();
        } else {
@@ -264,6 +271,7 @@ public class DataProcessManager {
    private void loadCurrentAppUsageList() {
        new AsyncTask<Void, Void, List<AppUsageEvent>>() {
            @Override
            @Nullable
            protected List<AppUsageEvent> doInBackground(Void... voids) {
                if (!shouldLoadAppUsageData()) {
                    Log.d(TAG, "not loadCurrentAppUsageList");
@@ -271,33 +279,21 @@ public class DataProcessManager {
                }
                final long startTime = System.currentTimeMillis();
                // Loads the current battery usage data from the battery stats service.
                final int currentUserId = getCurrentUserId();
                final int workProfileUserId = getWorkProfileUserId();
                final Map<Long, UsageEvents> usageEventsMap = new ArrayMap<>();
                for (int userId : mUserIdsSeries.getVisibleUserIds()) {
                    final UsageEvents usageEventsForCurrentUser =
                        DataProcessor.getAppUsageEventsForUser(
                                mContext, currentUserId, mRawStartTimestamp);
                // If fail to load usage events for current user, return null directly and screen-on
                // time will not be shown in the UI.
                            DataProcessor.getCurrentAppUsageEventsForUser(
                                    mContext, mUserIdsSeries, userId, mRawStartTimestamp);
                    if (usageEventsForCurrentUser == null) {
                    Log.w(TAG, "usageEventsForCurrentUser is null");
                        // If fail to load usage events for any user, return null directly and
                        // screen-on time will not be shown in the UI.
                        if (userId == mUserIdsSeries.getCurrentUserId()) {
                            return null;
                        }
                UsageEvents usageEventsForWorkProfile = null;
                if (workProfileUserId != Integer.MIN_VALUE) {
                    usageEventsForWorkProfile =
                            DataProcessor.getAppUsageEventsForUser(
                                    mContext, workProfileUserId, mRawStartTimestamp);
                    } else {
                    Log.d(TAG, "there is no work profile");
                        usageEventsMap.put(Long.valueOf(userId), usageEventsForCurrentUser);
                    }

                final Map<Long, UsageEvents> usageEventsMap = new ArrayMap<>();
                usageEventsMap.put(Long.valueOf(currentUserId), usageEventsForCurrentUser);
                if (usageEventsForWorkProfile != null) {
                    Log.d(TAG, "usageEventsForWorkProfile is null");
                    usageEventsMap.put(Long.valueOf(workProfileUserId), usageEventsForWorkProfile);
                }

                final List<AppUsageEvent> appUsageEventList =
                        DataProcessor.generateAppUsageEventListFromUsageEvents(
                                mContext, usageEventsMap);
@@ -337,7 +333,7 @@ public class DataProcessManager {
                        DatabaseUtils.getAppUsageEventForUsers(
                                mContext,
                                Calendar.getInstance(),
                                getCurrentUserIds(),
                                mUserIdsSeries.getVisibleUserIds(),
                                mRawStartTimestamp);
                Log.d(
                        TAG,
@@ -435,6 +431,7 @@ public class DataProcessManager {
                final Map<Long, BatteryDiffData> batteryDiffDataMap =
                        DataProcessor.getBatteryDiffDataMapFromStatsService(
                                mContext,
                                mUserIdsSeries,
                                mRawStartTimestamp,
                                getSystemAppsPackageNames(),
                                getSystemAppsUids());
@@ -514,6 +511,7 @@ public class DataProcessManager {
                batteryDiffDataMap.putAll(
                        DataProcessor.getBatteryDiffDataMap(
                                mContext,
                                mUserIdsSeries,
                                mHourlyBatteryLevelsPerDay,
                                mBatteryHistoryMap,
                                mAppUsagePeriodMap,
@@ -546,9 +544,8 @@ public class DataProcessManager {
        if (!mShowScreenOnTime) {
            return false;
        }
        final int currentUserId = getCurrentUserId();
        // If current user is locked, no need to load app usage data from service or database.
        if (mUserManager == null || !mUserManager.isUserUnlocked(currentUserId)) {
        if (mUserIdsSeries.isCurrentUserLocked()) {
            Log.d(TAG, "shouldLoadAppUsageData: false, current user is locked");
            mShowScreenOnTime = false;
            return false;
@@ -556,26 +553,6 @@ public class DataProcessManager {
        return true;
    }

    // Returns the list of current user id and work profile id if exists.
    private List<Integer> getCurrentUserIds() {
        final List<Integer> userIds = new ArrayList<>();
        userIds.add(getCurrentUserId());
        final int workProfileUserId = getWorkProfileUserId();
        if (workProfileUserId != Integer.MIN_VALUE) {
            userIds.add(workProfileUserId);
        }
        return userIds;
    }

    private int getCurrentUserId() {
        return mContext.getUserId();
    }

    private int getWorkProfileUserId() {
        final UserHandle userHandle = Utils.getManagedProfile(mUserManager);
        return userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
    }

    private synchronized Set<String> getSystemAppsPackageNames() {
        if (mSystemAppsPackageNames == null) {
            mSystemAppsPackageNames = DataProcessor.getSystemAppsPackageNames(mContext);
@@ -599,6 +576,7 @@ public class DataProcessManager {
    public static BatteryLevelData getBatteryLevelData(
            Context context,
            @Nullable Handler handler,
            final UserIdsSeries userIdsSeries,
            final boolean isFromPeriodJob,
            final OnBatteryDiffDataMapLoadedListener onBatteryUsageMapLoadedListener) {
        final long start = System.currentTimeMillis();
@@ -610,13 +588,14 @@ public class DataProcessManager {
                        lastFullChargeTime,
                        DatabaseUtils.BATTERY_LEVEL_RECORD_EVENTS);
        final long startTimestamp =
                batteryLevelRecordEvents.isEmpty()
                (batteryLevelRecordEvents.isEmpty() || !userIdsSeries.isMainUserProfileOnly())
                        ? lastFullChargeTime
                        : batteryLevelRecordEvents.get(0).getTimestamp();
        final BatteryLevelData batteryLevelData =
                getPeriodBatteryLevelData(
                        context,
                        handler,
                        userIdsSeries,
                        startTimestamp,
                        lastFullChargeTime,
                        isFromPeriodJob,
@@ -636,6 +615,7 @@ public class DataProcessManager {
    private static BatteryLevelData getPeriodBatteryLevelData(
            Context context,
            @Nullable Handler handler,
            final UserIdsSeries userIdsSeries,
            final long startTimestamp,
            final long lastFullChargeTime,
            final boolean isFromPeriodJob,
@@ -663,7 +643,9 @@ public class DataProcessManager {
                                lastFullChargeTime);
        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
            Log.d(TAG, "batteryHistoryMap is null in getPeriodBatteryLevelData()");
            new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
            new DataProcessManager(
                            context, handler, userIdsSeries, onBatteryDiffDataMapLoadedListener)
                    .start();
            return null;
        }

@@ -675,7 +657,9 @@ public class DataProcessManager {
                DataProcessor.getLevelDataThroughProcessedHistoryMap(
                        context, processedBatteryHistoryMap);
        if (batteryLevelData == null) {
            new DataProcessManager(context, handler, onBatteryDiffDataMapLoadedListener).start();
            new DataProcessManager(
                            context, handler, userIdsSeries, onBatteryDiffDataMapLoadedListener)
                    .start();
            Log.d(TAG, "getBatteryLevelData() returns null");
            return null;
        }
@@ -684,6 +668,7 @@ public class DataProcessManager {
        new DataProcessManager(
                        context,
                        handler,
                        userIdsSeries,
                        startTimestamp,
                        lastFullChargeTime,
                        onBatteryDiffDataMapLoadedListener,
+26 −43
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.BatteryConsumer;
import android.os.BatteryStatsManager;
import android.os.BatteryUsageStats;
@@ -52,7 +51,6 @@ import androidx.annotation.Nullable;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.PowerProfile;
import com.android.settings.Utils;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.fuelgauge.BatteryStatus;
@@ -134,6 +132,7 @@ public final class DataProcessor {
    @Nullable
    public static Map<Integer, Map<Integer, BatteryDiffData>> getBatteryUsageData(
            Context context,
            UserIdsSeries userIdsSeries,
            @Nullable final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap) {
        if (batteryHistoryMap == null || batteryHistoryMap.isEmpty()) {
            Log.d(TAG, "getBatteryLevelData() returns null");
@@ -161,6 +160,7 @@ public final class DataProcessor {
                        context,
                        getBatteryDiffDataMap(
                                context,
                                userIdsSeries,
                                batteryLevelData.getHourlyBatteryLevelsPerDay(),
                                processedBatteryHistoryMap,
                                /* appUsagePeriodMap= */ null,
@@ -183,24 +183,21 @@ public final class DataProcessor {

    /** Gets the {@link UsageEvents} from system service for all unlocked users. */
    @Nullable
    public static Map<Long, UsageEvents> getAppUsageEvents(Context context) {
    public static Map<Long, UsageEvents> getAppUsageEvents(
            Context context, UserIdsSeries userIdsSeries) {
        final long start = System.currentTimeMillis();
        context = DatabaseUtils.getParentContext(context);
        if (context == null) {
            return null;
        }
        final Map<Long, UsageEvents> resultMap = new ArrayMap();
        final UserManager userManager = context.getSystemService(UserManager.class);
        if (userManager == null) {
            return null;
        }
        final long sixDaysAgoTimestamp =
                DatabaseUtils.getTimestampSixDaysAgo(Calendar.getInstance());
        for (final UserInfo user : userManager.getAliveUsers()) {
        for (final int userId : userIdsSeries.getVisibleUserIds()) {
            final UsageEvents events =
                    getAppUsageEventsForUser(context, userManager, user.id, sixDaysAgoTimestamp);
                    getAppUsageEventsForUser(context, userIdsSeries, userId, sixDaysAgoTimestamp);
            if (events != null) {
                resultMap.put(Long.valueOf(user.id), events);
                resultMap.put(Long.valueOf(userId), events);
            }
        }
        final long elapsedTime = System.currentTimeMillis() - start;
@@ -212,22 +209,21 @@ public final class DataProcessor {

    /** Gets the {@link UsageEvents} from system service for the specific user. */
    @Nullable
    public static UsageEvents getAppUsageEventsForUser(
            Context context, final int userID, final long startTimestampOfLevelData) {
    public static UsageEvents getCurrentAppUsageEventsForUser(
            Context context,
            final UserIdsSeries userIdsSeries,
            final int userID,
            final long startTimestampOfLevelData) {
        final long start = System.currentTimeMillis();
        context = DatabaseUtils.getParentContext(context);
        if (context == null) {
            return null;
        }
        final UserManager userManager = context.getSystemService(UserManager.class);
        if (userManager == null) {
            return null;
        }
        final long sixDaysAgoTimestamp =
                DatabaseUtils.getTimestampSixDaysAgo(Calendar.getInstance());
        final long earliestTimestamp = Math.max(sixDaysAgoTimestamp, startTimestampOfLevelData);
        final UsageEvents events =
                getAppUsageEventsForUser(context, userManager, userID, earliestTimestamp);
                getAppUsageEventsForUser(context, userIdsSeries, userID, earliestTimestamp);
        final long elapsedTime = System.currentTimeMillis() - start;
        Log.d(
                TAG,
@@ -521,6 +517,7 @@ public final class DataProcessor {

    static Map<Long, BatteryDiffData> getBatteryDiffDataMap(
            Context context,
            final UserIdsSeries userIdsSeries,
            final List<BatteryLevelData.PeriodBatteryLevelData> hourlyBatteryLevelsPerDay,
            final Map<Long, Map<String, BatteryHistEntry>> batteryHistoryMap,
            final Map<Integer, Map<Integer, Map<Long, Map<String, List<AppUsagePeriod>>>>>
@@ -528,11 +525,6 @@ public final class DataProcessor {
            final @NonNull Set<String> systemAppsPackageNames,
            final @NonNull Set<Integer> systemAppsUids) {
        final Map<Long, BatteryDiffData> batteryDiffDataMap = new ArrayMap<>();
        final int currentUserId = context.getUserId();
        final UserHandle userHandle =
                Utils.getManagedProfile(context.getSystemService(UserManager.class));
        final int workProfileUserId =
                userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;
        // Each time slot usage diff data =
        //     sum(Math.abs(timestamp[i+1] data - timestamp[i] data));
        // since we want to aggregate every hour usage diff data into a single time slot.
@@ -569,8 +561,7 @@ public final class DataProcessor {
                                endTimestamp,
                                startBatteryLevel,
                                endBatteryLevel,
                                currentUserId,
                                workProfileUserId,
                                userIdsSeries,
                                slotDuration,
                                systemAppsPackageNames,
                                systemAppsUids,
@@ -629,6 +620,7 @@ public final class DataProcessor {
    @Nullable
    static BatteryDiffData generateBatteryDiffData(
            final Context context,
            final UserIdsSeries userIdsSeries,
            final long startTimestamp,
            final List<BatteryHistEntry> batteryHistEntryList,
            final @NonNull Set<String> systemAppsPackageNames,
@@ -650,15 +642,9 @@ public final class DataProcessor {
                    systemAppsUids,
                    /* isAccumulated= */ false);
        }
        final int currentUserId = context.getUserId();
        final UserHandle userHandle =
                Utils.getManagedProfile(context.getSystemService(UserManager.class));
        final int workProfileUserId =
                userHandle != null ? userHandle.getIdentifier() : Integer.MIN_VALUE;

        for (BatteryHistEntry entry : batteryHistEntryList) {
            final boolean isFromOtherUsers =
                    isConsumedFromOtherUsers(currentUserId, workProfileUserId, entry);
                    isConsumedFromOtherUsers(userIdsSeries, entry);
            // Not show other users' battery usage data.
            if (isFromOtherUsers) {
                continue;
@@ -905,6 +891,7 @@ public final class DataProcessor {

    static Map<Long, BatteryDiffData> getBatteryDiffDataMapFromStatsService(
            final Context context,
            final UserIdsSeries userIdsSeries,
            final long startTimestamp,
            @NonNull final Set<String> systemAppsPackageNames,
            @NonNull final Set<Integer> systemAppsUids) {
@@ -913,6 +900,7 @@ public final class DataProcessor {
                startTimestamp,
                generateBatteryDiffData(
                        context,
                        userIdsSeries,
                        startTimestamp,
                        getBatteryHistListFromFromStatsService(context),
                        systemAppsPackageNames,
@@ -1034,14 +1022,14 @@ public final class DataProcessor {
    @Nullable
    private static UsageEvents getAppUsageEventsForUser(
            Context context,
            final UserManager userManager,
            final UserIdsSeries userIdsSeries,
            final int userID,
            final long earliestTimestamp) {
        final String callingPackage = context.getPackageName();
        final long now = System.currentTimeMillis();
        // When the user is not unlocked, UsageStatsManager will return null, so bypass the
        // following data loading logics directly.
        if (!userManager.isUserUnlocked(userID)) {
        if (userIdsSeries.isUserLocked(userID)) {
            Log.w(TAG, "fail to load app usage event for user :" + userID + " because locked");
            return null;
        }
@@ -1331,8 +1319,7 @@ public final class DataProcessor {
            final long endTimestamp,
            final int startBatteryLevel,
            final int endBatteryLevel,
            final int currentUserId,
            final int workProfileUserId,
            final UserIdsSeries userIdsSeries,
            final long slotDuration,
            final Set<String> systemAppsPackageNames,
            final Set<Integer> systemAppsUids,
@@ -1342,8 +1329,7 @@ public final class DataProcessor {
        if (appUsageMap != null) {
            final List<AppUsagePeriod> flatAppUsagePeriodList = new ArrayList<>();
            for (final long userId : appUsageMap.keySet()) {
                if ((userId != currentUserId && userId != workProfileUserId)
                        || appUsageMap.get(userId) == null) {
                if (userIdsSeries.isFromOtherUsers(userId) || appUsageMap.get(userId) == null) {
                    continue;
                }
                for (final String packageName : appUsageMap.get(userId).keySet()) {
@@ -1405,8 +1391,7 @@ public final class DataProcessor {

            // Not show other users' battery usage data.
            final boolean isFromOtherUsers =
                    isConsumedFromOtherUsers(
                            currentUserId, workProfileUserId, selectedBatteryEntry);
                    isConsumedFromOtherUsers(userIdsSeries, selectedBatteryEntry);
            if (isFromOtherUsers) {
                continue;
            }
@@ -1593,12 +1578,10 @@ public final class DataProcessor {
    }

    private static boolean isConsumedFromOtherUsers(
            final int currentUserId,
            final int workProfileUserId,
            final UserIdsSeries userIdsSeries,
            final BatteryHistEntry batteryHistEntry) {
        return isUidConsumer(batteryHistEntry.mConsumerType)
                && batteryHistEntry.mUserId != currentUserId
                && batteryHistEntry.mUserId != workProfileUserId;
                && userIdsSeries.isFromOtherUsers(batteryHistEntry.mUserId);
    }

    @Nullable
+1 −0
Original line number Diff line number Diff line
@@ -492,6 +492,7 @@ public class PowerUsageAdvanced extends PowerUsageBase {
                    return DataProcessManager.getBatteryLevelData(
                            getContext(),
                            mHandler,
                            new UserIdsSeries(getContext(), /* mainUserOnly= */ false),
                            /* isFromPeriodJob= */ false,
                            PowerUsageAdvanced.this::onBatteryDiffDataMapUpdate);
                }
Loading