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

Commit 013d3f63 authored by jackqdyulei's avatar jackqdyulei
Browse files

Use BatteryStatsLoader in InstalledAppDetails

InstalledAppDetails uses AsyncTask to update foreground mBatteryStatsHelper
in background thread, which is dangerous. This cl make
InstalledAppDetails use BatteryStatsLoader to update batteryStatsHelper
and only assign it once in UI thread.

Bug: 38497555
Test: RunSettingsRoboTests
Change-Id: I3078b60a2dae36995ae5f925b4d49e36e79bddfd
parent d6aa9f34
Loading
Loading
Loading
Loading
+42 −30
Original line number Diff line number Diff line
@@ -93,6 +93,7 @@ import com.android.settings.datausage.DataUsageList;
import com.android.settings.datausage.DataUsageSummary;
import com.android.settings.fuelgauge.AdvancedPowerUsageDetail;
import com.android.settings.fuelgauge.BatteryEntry;
import com.android.settings.fuelgauge.BatteryStatsHelperLoader;
import com.android.settings.fuelgauge.BatteryUtils;
import com.android.settings.notification.AppNotificationSettings;
import com.android.settings.notification.NotificationBackend;
@@ -143,6 +144,7 @@ public class InstalledAppDetails extends AppInfoBase

    private static final int LOADER_CHART_DATA = 2;
    private static final int LOADER_STORAGE = 3;
    private static final int LOADER_BATTERY = 4;

    private static final int DLG_FORCE_STOP = DLG_BASE + 1;
    private static final int DLG_DISABLE = DLG_BASE + 2;
@@ -204,6 +206,31 @@ public class InstalledAppDetails extends AppInfoBase
    private String mBatteryPercent;
    private BatteryUtils mBatteryUtils;

    private final LoaderCallbacks<BatteryStatsHelper> mBatteryCallbacks =
            new LoaderCallbacks<BatteryStatsHelper>() {

                @Override
                public Loader<BatteryStatsHelper> onCreateLoader(int id, Bundle args) {
                    return new BatteryStatsHelperLoader(getContext(), args);
                }

                @Override
                public void onLoadFinished(Loader<BatteryStatsHelper> loader,
                        BatteryStatsHelper batteryHelper) {
                    mBatteryHelper = batteryHelper;
                    if (mPackageInfo != null) {
                        mSipper = findTargetSipper(batteryHelper, mPackageInfo.applicationInfo.uid);
                        if (getActivity() != null) {
                            updateBattery();
                        }
                    }
                }

                @Override
                public void onLoaderReset(Loader<BatteryStatsHelper> loader) {
                }
            };

    private boolean handleDisableable(Button button) {
        boolean disableable = false;
        // Try to prevent the user from bricking their phone
@@ -362,7 +389,6 @@ public class InstalledAppDetails extends AppInfoBase
        } else {
            removePreference(KEY_DATA);
        }
        mBatteryHelper = new BatteryStatsHelper(getActivity(), true);
        mBatteryUtils = BatteryUtils.getInstance(getContext());
    }

@@ -386,7 +412,7 @@ public class InstalledAppDetails extends AppInfoBase
                    mDataCallbacks);
            loaderManager.restartLoader(LOADER_STORAGE, Bundle.EMPTY, this);
        }
        new BatteryUpdater().execute();
        getLoaderManager().initLoader(LOADER_BATTERY, Bundle.EMPTY, mBatteryCallbacks);
        new MemoryUpdater().execute();
        updateDynamicPrefs();
    }
@@ -625,6 +651,19 @@ public class InstalledAppDetails extends AppInfoBase
        return showIt;
    }

    @VisibleForTesting
    BatterySipper findTargetSipper(BatteryStatsHelper batteryHelper, int uid) {
        List<BatterySipper> usageList = batteryHelper.getUsageList();
        for (int i = 0, size = usageList.size(); i < size; i++) {
            BatterySipper sipper = usageList.get(i);
            if (sipper.getUid() == uid) {
                return sipper;
            }
        }

        return null;
    }

    private boolean signaturesMatch(String pkg1, String pkg2) {
        if (pkg1 != null && pkg2 != null) {
            try {
@@ -719,7 +758,7 @@ public class InstalledAppDetails extends AppInfoBase
    }

    private void updateBattery() {
        if (mSipper != null) {
        if (mSipper != null && mBatteryHelper != null) {
            mBatteryPreference.setEnabled(true);
            final int dischargeAmount = mBatteryHelper.getStats().getDischargeAmount(
                    BatteryStats.STATS_SINCE_CHARGED);
@@ -1343,33 +1382,6 @@ public class InstalledAppDetails extends AppInfoBase

    }

    private class BatteryUpdater extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... params) {
            mBatteryHelper.create((Bundle) null);
            mBatteryHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED,
                    mUserManager.getUserProfiles());
            List<BatterySipper> usageList = mBatteryHelper.getUsageList();
            final int N = usageList.size();
            for (int i = 0; i < N; i++) {
                BatterySipper sipper = usageList.get(i);
                if (sipper.getUid() == mPackageInfo.applicationInfo.uid) {
                    mSipper = sipper;
                    break;
                }
            }
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (getActivity() == null) {
                return;
            }
            refreshUi();
        }
    }

    /**
     * Elicit this class for testing. Test cannot be done in robolectric because it
     * invokes the new API.
+21 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.settings.applications;


import static com.google.common.truth.Truth.assertThat;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
@@ -65,12 +66,17 @@ import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
import org.robolectric.util.ReflectionHelpers;

import java.util.ArrayList;
import java.util.List;


@RunWith(SettingsRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
public final class InstalledAppDetailsTest {

    private static final String PACKAGE_NAME = "test_package_name";
    private static final int TARGET_UID = 111;
    private static final int OTHER_UID = 222;

    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
    private Context mContext;
@@ -87,6 +93,8 @@ public final class InstalledAppDetailsTest {
    @Mock
    private BatterySipper mBatterySipper;
    @Mock
    private BatterySipper mOtherBatterySipper;
    @Mock
    private BatteryStatsHelper mBatteryStatsHelper;
    @Mock
    private BatteryStats.Uid mUid;
@@ -105,6 +113,8 @@ public final class InstalledAppDetailsTest {

        mBatterySipper.drainType = BatterySipper.DrainType.IDLE;
        mBatterySipper.uidObj = mUid;
        doReturn(TARGET_UID).when(mBatterySipper).getUid();
        doReturn(OTHER_UID).when(mOtherBatterySipper).getUid();
        doReturn(mActivity).when(mAppDetail).getActivity();
        doReturn(mShadowContext).when(mAppDetail).getContext();
        doReturn(mPackageManager).when(mActivity).getPackageManager();
@@ -388,4 +398,15 @@ public final class InstalledAppDetailsTest {

        verify(mActivity).invalidateOptionsMenu();
    }

    @Test
    public void findTargetSipper_findCorrectSipper() {
        List<BatterySipper> usageList = new ArrayList<>();
        usageList.add(mBatterySipper);
        usageList.add(mOtherBatterySipper);
        doReturn(usageList).when(mBatteryStatsHelper).getUsageList();

        assertThat(mAppDetail.findTargetSipper(mBatteryStatsHelper, TARGET_UID)).isEqualTo(
                mBatterySipper);
    }
}