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

Commit 8603ad42 authored by Daniel Nishi's avatar Daniel Nishi Committed by Android (Google) Code Review
Browse files

Merge "Use the fast track for the AppCollector."

parents af47f67d d7b0329a
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@ package android.content.pm;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
import android.text.TextUtils;

import java.util.Objects;

/**
 * implementation of PackageStats associated with a
@@ -173,4 +176,31 @@ public class PackageStats implements Parcelable {
        dest.writeLong(externalMediaSize);
        dest.writeLong(externalObbSize);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof PackageStats)) {
            return false;
        }

        final PackageStats otherStats = (PackageStats) obj;
        return ((TextUtils.equals(packageName, otherStats.packageName))
                && userHandle == otherStats.userHandle
                && codeSize == otherStats.codeSize
                && dataSize == otherStats.dataSize
                && cacheSize == otherStats.cacheSize
                && externalCodeSize == otherStats.externalCodeSize
                && externalDataSize == otherStats.externalDataSize
                && externalCacheSize == otherStats.externalCacheSize
                && externalMediaSize == otherStats.externalMediaSize
                && externalObbSize == otherStats.externalObbSize);
    }

    @Override
    public int hashCode() {
        return Objects.hash(packageName, userHandle, codeSize, dataSize,
                cacheSize, externalCodeSize, externalDataSize, externalCacheSize, externalMediaSize,
                externalObbSize);
    }

}
+18 −28
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.storage;

import android.annotation.NonNull;
import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
@@ -64,7 +66,8 @@ public class AppCollector {
        mBackgroundHandler = new BackgroundHandler(BackgroundThread.get().getLooper(),
                volume,
                context.getPackageManager(),
                (UserManager) context.getSystemService(Context.USER_SERVICE));
                (UserManager) context.getSystemService(Context.USER_SERVICE),
                (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE));
    }

    /**
@@ -93,39 +96,20 @@ public class AppCollector {
        return value;
    }

    private class StatsObserver extends IPackageStatsObserver.Stub {
        private AtomicInteger mCount;
        private final ArrayList<PackageStats> mPackageStats;

        public StatsObserver(int count) {
            mCount = new AtomicInteger(count);
            mPackageStats = new ArrayList<>(count);
        }

        @Override
        public void onGetStatsCompleted(PackageStats packageStats, boolean succeeded)
                throws RemoteException {
            if (succeeded) {
                mPackageStats.add(packageStats);
            }

            if (mCount.decrementAndGet() == 0) {
                mStats.complete(mPackageStats);
            }
        }
    }

    private class BackgroundHandler extends Handler {
        static final int MSG_START_LOADING_SIZES = 0;
        private final VolumeInfo mVolume;
        private final PackageManager mPm;
        private final UserManager mUm;
        private final StorageStatsManager mStorageStatsManager;

        BackgroundHandler(Looper looper, @NonNull VolumeInfo volume, PackageManager pm, UserManager um) {
        BackgroundHandler(Looper looper, @NonNull VolumeInfo volume,
                PackageManager pm, UserManager um, StorageStatsManager storageStatsManager) {
            super(looper);
            mVolume = volume;
            mPm = pm;
            mUm = um;
            mStorageStatsManager = storageStatsManager;
        }

        @Override
@@ -149,14 +133,20 @@ public class AppCollector {
                        mStats.complete(new ArrayList<>());
                    }

                    // Kick off the async package size query for all apps.
                    final StatsObserver observer = new StatsObserver(count);
                    List<PackageStats> stats = new ArrayList<>();
                    for (UserInfo user : users) {
                        for (ApplicationInfo app : volumeApps) {
                            mPm.getPackageSizeInfoAsUser(app.packageName, user.id,
                                    observer);
                            PackageStats packageStats = new PackageStats(app.packageName, user.id);
                            StorageStats storageStats = mStorageStatsManager.queryStatsForPackage(
                                    app.volumeUuid, app.packageName, user.getUserHandle());
                            packageStats.cacheSize = storageStats.getCacheBytes();
                            packageStats.codeSize = storageStats.getCodeBytes();
                            packageStats.dataSize = storageStats.getDataBytes();
                            stats.add(packageStats);
                        }
                    }

                    mStats.complete(stats);
                }
            }
        }
+13 −70
Original line number Diff line number Diff line
@@ -16,12 +16,15 @@

package com.android.server.storage;

import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.pm.UserInfo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.VolumeInfo;
import android.test.AndroidTestCase;
@@ -53,6 +56,7 @@ public class AppCollectorTest extends AndroidTestCase {
    @Mock private Context mContext;
    @Mock private PackageManager mPm;
    @Mock private UserManager mUm;
    @Mock private StorageStatsManager mSsm;
    private List<ApplicationInfo> mApps;
    private List<UserInfo> mUsers;

@@ -63,6 +67,7 @@ public class AppCollectorTest extends AndroidTestCase {
        mApps = new ArrayList<>();
        when(mContext.getPackageManager()).thenReturn(mPm);
        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUm);
        when(mContext.getSystemService(Context.STORAGE_STATS_SERVICE)).thenReturn(mSsm);

        // Set up the app list.
        when(mPm.getInstalledApplications(anyInt())).thenReturn(mApps);
@@ -100,39 +105,9 @@ public class AppCollectorTest extends AndroidTestCase {
        AppCollector collector = new AppCollector(mContext, volume);
        PackageStats stats = new PackageStats("com.test.app");

        // Set up this to handle the asynchronous call to the PackageManager. This returns the
        // package info for the specified package.
        doAnswer(new Answer<Void>() {
             @Override
             public Void answer(InvocationOnMock invocation) {
                 try {
                     ((IPackageStatsObserver.Stub) invocation.getArguments()[2])
                             .onGetStatsCompleted(stats, true);
                 } catch (Exception e) {
                     // We fail instead of just letting the exception fly because throwing
                     // out of the callback like this on the background thread causes the test
                     // runner to crash, rather than reporting the failure.
                     fail();
                 }
                 return null;
             }
        }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any());


        // Because getPackageStats is a blocking call, we block execution of the test until the
        // call finishes. In order to finish the call, we need the above answer to execute.
        List<PackageStats> myStats = new ArrayList<>();
        CountDownLatch latch = new CountDownLatch(1);
        new Thread(new Runnable() {
            @Override
            public void run() {
                myStats.addAll(collector.getPackageStats(TIMEOUT));
                latch.countDown();
            }
        }).start();
        latch.await();

        assertThat(myStats).containsExactly(stats);
        when(mSsm.queryStatsForPackage(eq("testuuid"),
                eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats());
        assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats);
    }

    @Test
@@ -151,43 +126,11 @@ public class AppCollectorTest extends AndroidTestCase {
        PackageStats otherStats = new PackageStats("com.test.app");
        otherStats.userHandle = 1;

        // Set up this to handle the asynchronous call to the PackageManager. This returns the
        // package info for our packages.
        doAnswer(new Answer<Void>() {
             @Override
             public Void answer(InvocationOnMock invocation) {
                 try {
                     ((IPackageStatsObserver.Stub) invocation.getArguments()[2])
                             .onGetStatsCompleted(stats, true);

                     // Now callback for the other uid.
                     ((IPackageStatsObserver.Stub) invocation.getArguments()[2])
                             .onGetStatsCompleted(otherStats, true);
                 } catch (Exception e) {
                     // We fail instead of just letting the exception fly because throwing
                     // out of the callback like this on the background thread causes the test
                     // runner to crash, rather than reporting the failure.
                     fail();
                 }
                 return null;
             }
        }).when(mPm).getPackageSizeInfoAsUser(eq("com.test.app"), eq(0), any());


        // Because getPackageStats is a blocking call, we block execution of the test until the
        // call finishes. In order to finish the call, we need the above answer to execute.
        List<PackageStats> myStats = new ArrayList<>();
        CountDownLatch latch = new CountDownLatch(1);
        new Thread(new Runnable() {
            @Override
            public void run() {
                myStats.addAll(collector.getPackageStats(TIMEOUT));
                latch.countDown();
            }
        }).start();
        latch.await();

        assertThat(myStats).containsAllOf(stats, otherStats);
        when(mSsm.queryStatsForPackage(eq("testuuid"),
                eq("com.test.app"), eq(UserHandle.of(0)))).thenReturn(new StorageStats());
        when(mSsm.queryStatsForPackage(eq("testuuid"),
                eq("com.test.app"), eq(UserHandle.of(1)))).thenReturn(new StorageStats());
        assertThat(collector.getPackageStats(TIMEOUT)).containsExactly(stats, otherStats);
    }

    @Test(expected=NullPointerException.class)