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

Commit fa1ef8d3 authored by WyattRiley's avatar WyattRiley
Browse files

Adding History of Location Requests to Dumpsys

Bug: 141716920
Test: m -j ROBOTEST_FILTER=LocationRequestStatisticsTest RunFrameworksServicesRoboTests
Test: On device verified history
Change-Id: Ia862e64415ef6132422ea3b2f1a22197e9b44c44
parent 3c8a4321
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3192,6 +3192,8 @@ public class LocationManagerService extends ILocationManager.Stub {
            }
            ipw.decreaseIndent();

            mRequestStatistics.history.dump(ipw);

            ipw.println("Last Known Locations:");
            ipw.increaseIndent();
            for (Map.Entry<String, Location> entry : mLastLocation.entrySet()) {
+124 −1
Original line number Diff line number Diff line
/*
 * Copyright 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.location;

import android.os.SystemClock;
import android.util.Log;
import android.util.TimeUtils;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;

import java.util.ArrayList;
import java.util.HashMap;

/**
@@ -17,6 +38,8 @@ public class LocationRequestStatistics {
    public final HashMap<PackageProviderKey, PackageStatistics> statistics
            = new HashMap<PackageProviderKey, PackageStatistics>();

    public final RequestSummaryLimitedHistory history = new RequestSummaryLimitedHistory();

    /**
     * Signals that a package has started requesting locations.
     *
@@ -34,6 +57,7 @@ public class LocationRequestStatistics {
        }
        stats.startRequesting(intervalMs);
        stats.updateForeground(isForeground);
        history.addRequest(packageName, providerName, intervalMs);
    }

    /**
@@ -48,6 +72,7 @@ public class LocationRequestStatistics {
        if (stats != null) {
            stats.stopRequesting();
        }
        history.removeRequest(packageName, providerName);
    }

    /**
@@ -77,7 +102,7 @@ public class LocationRequestStatistics {
         */
        public final String providerName;

        public PackageProviderKey(String packageName, String providerName) {
        PackageProviderKey(String packageName, String providerName) {
            this.packageName = packageName;
            this.providerName = providerName;
        }
@@ -99,6 +124,104 @@ public class LocationRequestStatistics {
        }
    }

    /**
     * A data structure to hold past requests
     */
    public static class RequestSummaryLimitedHistory {
        @VisibleForTesting
        static final int MAX_SIZE = 100;

        final ArrayList<RequestSummary> mList = new ArrayList<>(MAX_SIZE);

        /**
         * Append an added location request to the history
         */
        @VisibleForTesting
        void addRequest(String packageName, String providerName, long intervalMs) {
            addRequestSummary(new RequestSummary(packageName, providerName, intervalMs));
        }

        /**
         * Append a removed location request to the history
         */
        @VisibleForTesting
        void removeRequest(String packageName, String providerName) {
            addRequestSummary(new RequestSummary(
                    packageName, providerName, RequestSummary.REQUEST_ENDED_INTERVAL));
        }

        private void addRequestSummary(RequestSummary summary) {
            while (mList.size() >= MAX_SIZE) {
                mList.remove(0);
            }
            mList.add(summary);
        }

        /**
         * Dump history to a printwriter (for dumpsys location)
         */
        public void dump(IndentingPrintWriter ipw) {
            long systemElapsedOffsetMillis = System.currentTimeMillis()
                    - SystemClock.elapsedRealtime();

            ipw.println("Last Several Location Requests:");
            ipw.increaseIndent();

            for (RequestSummary requestSummary : mList) {
                requestSummary.dump(ipw, systemElapsedOffsetMillis);
            }

            ipw.decreaseIndent();
        }
    }

    /**
     * A data structure to hold a single request
     */
    static class RequestSummary {
        /**
         * Name of package requesting location.
         */
        private final String mPackageName;
        /**
         * Name of provider being requested (e.g. "gps").
         */
        private final String mProviderName;
        /**
         * Interval Requested, or REQUEST_ENDED_INTERVAL indicating request has ended
         */
        private final long mIntervalMillis;
        /**
         * Elapsed time of request
         */
        private final long mElapsedRealtimeMillis;

        /**
         * Placeholder for requested ending (other values indicate request started/changed)
         */
        static final long REQUEST_ENDED_INTERVAL = -1;

        RequestSummary(String packageName, String providerName, long intervalMillis) {
            this.mPackageName = packageName;
            this.mProviderName = providerName;
            this.mIntervalMillis = intervalMillis;
            this.mElapsedRealtimeMillis = SystemClock.elapsedRealtime();
        }

        void dump(IndentingPrintWriter ipw, long systemElapsedOffsetMillis) {
            StringBuilder s = new StringBuilder();
            long systemTimeMillis = systemElapsedOffsetMillis + mElapsedRealtimeMillis;
            s.append("At ").append(TimeUtils.formatForLogging(systemTimeMillis)).append(": ")
                    .append(mIntervalMillis == REQUEST_ENDED_INTERVAL ? "- " : "+ ")
                    .append(String.format("%7s", mProviderName)).append(" request from ")
                    .append(mPackageName);
            if (mIntervalMillis != REQUEST_ENDED_INTERVAL) {
                s.append(" at interval ").append(mIntervalMillis / 1000).append(" seconds");
            }
            ipw.println(s);
        }
    }

    /**
     * Usage statistics for a package/provider pair.
     */
+74 −0
Original line number Diff line number Diff line
/*
 * Copyright 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.location;

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

import android.platform.test.annotations.Presubmit;

import com.android.internal.util.IndentingPrintWriter;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;

import java.io.PrintWriter;
import java.io.StringWriter;

/**
 * Unit tests for {@link LocationRequestStatistics}.
 */
@RunWith(RobolectricTestRunner.class)
@Presubmit
public class LocationRequestStatisticsTest {

    /**
     * Check adding and removing requests & strings
     */
    @Test
    public void testRequestSummary() {
        LocationRequestStatistics.RequestSummary summary =
                new LocationRequestStatistics.RequestSummary(
                "com.example", "gps", 1000);
        StringWriter stringWriter = new StringWriter();
        summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriter), "  "), 1234);
        assertThat(stringWriter.toString()).startsWith("At");

        StringWriter stringWriterRemove = new StringWriter();
        summary = new LocationRequestStatistics.RequestSummary(
                "com.example", "gps",
                LocationRequestStatistics.RequestSummary.REQUEST_ENDED_INTERVAL);
        summary.dump(new IndentingPrintWriter(new PrintWriter(stringWriterRemove), "  "), 2345);
        assertThat(stringWriterRemove.toString()).contains("-");
    }

    /**
     * Check summary list size capping
     */
    @Test
    public void testSummaryList() {
        LocationRequestStatistics statistics = new LocationRequestStatistics();
        statistics.history.addRequest("com.example", "gps", 1000);
        assertThat(statistics.history.mList.size()).isEqualTo(1);
        // Try (not) to overflow
        for (int i = 0; i < LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE; i++) {
            statistics.history.addRequest("com.example", "gps", 1000);
        }
        assertThat(statistics.history.mList.size()).isEqualTo(
                LocationRequestStatistics.RequestSummaryLimitedHistory.MAX_SIZE);
    }
}