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

Commit 87dcc5e1 authored by Kunal Malhotra's avatar Kunal Malhotra Committed by Automerger Merge Worker
Browse files

Merge "Updating foreground service type logger to log the duration of APIs and...

Merge "Updating foreground service type logger to log the duration of APIs and adding additional logging of FGS starts." into udc-dev am: 2537e164 am: c196ce5f

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



Change-Id: I95696a14281655bc83523871ae76ee2a5acc6cd3
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents d11f6e43 c196ce5f
Loading
Loading
Loading
Loading
+8 −3
Original line number Original line Diff line number Diff line
@@ -8254,12 +8254,14 @@ public final class ActiveServices {
                r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mDelegationService
                r.mFgsDelegation != null ? r.mFgsDelegation.mOptions.mDelegationService
                        : ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT,
                        : ForegroundServiceDelegationOptions.DELEGATION_SERVICE_DEFAULT,
                0 /* api_sate */,
                0 /* api_sate */,
                null /* api_type */,
                0 /* api_type */,
                null /* api_timestamp */,
                0 /* api_timestamp */,
                mAm.getUidStateLocked(r.appInfo.uid),
                mAm.getUidStateLocked(r.appInfo.uid),
                mAm.getUidProcessCapabilityLocked(r.appInfo.uid),
                mAm.getUidProcessCapabilityLocked(r.appInfo.uid),
                mAm.getUidStateLocked(r.mRecentCallingUid),
                mAm.getUidStateLocked(r.mRecentCallingUid),
                mAm.getUidProcessCapabilityLocked(r.mRecentCallingUid));
                mAm.getUidProcessCapabilityLocked(r.mRecentCallingUid),
                0,
                0);


        int event = 0;
        int event = 0;
        if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) {
        if (state == FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER) {
@@ -8434,6 +8436,9 @@ public final class ActiveServices {
                true, false, null, false,
                true, false, null, false,
                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
                AppOpsManager.ATTRIBUTION_FLAGS_NONE, AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE);
        registerAppOpCallbackLocked(r);
        registerAppOpCallbackLocked(r);
        synchronized (mFGSLogger) {
            mFGSLogger.logForegroundServiceStart(r.appInfo.uid, 0, r);
        }
        logFGSStateChangeLocked(r,
        logFGSStateChangeLocked(r,
                FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
                FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED__STATE__ENTER,
                0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN);
                0, FGS_STOP_REASON_UNKNOWN, FGS_TYPE_POLICY_CHECK_UNKNOWN);
+41 −29
Original line number Original line Diff line number Diff line
@@ -105,6 +105,11 @@ public class ForegroundServiceTypeLoggerModule {
        // to another ordered map, keyed by the component name
        // to another ordered map, keyed by the component name
        // to facilitate removing the record from the structure
        // to facilitate removing the record from the structure
        final SparseArray<ArrayMap<ComponentName, ServiceRecord>> mRunningFgs = new SparseArray<>();
        final SparseArray<ArrayMap<ComponentName, ServiceRecord>> mRunningFgs = new SparseArray<>();

        // A map of API types to last FGS stop call timestamps
        // We use this to get the duration an API was active after
        // the stop call.
        final SparseArray<Long> mLastFgsTimeStamp = new SparseArray<>();
    }
    }


    // SparseArray that tracks all UIDs that have made various
    // SparseArray that tracks all UIDs that have made various
@@ -167,17 +172,13 @@ public class ForegroundServiceTypeLoggerModule {
        }
        }
        if (!apiTypesFound.isEmpty()) {
        if (!apiTypesFound.isEmpty()) {
            // log a state change
            // log a state change
            int[] types = new int[apiTypesFound.size()];
            long[] timestamps = new long[apiTypesFound.size()];
            for (int i = 0, size = apiTypesFound.size(); i < size; i++) {
            for (int i = 0, size = apiTypesFound.size(); i < size; i++) {
                types[i] = apiTypesFound.get(i);
                timestamps[i] = timestampsFound.get(i);
            }
                logFgsApiEvent(record,
                logFgsApiEvent(record,
                        FGS_STATE_CHANGED_API_CALL,
                        FGS_STATE_CHANGED_API_CALL,
                        FGS_API_BEGIN_WITH_FGS,
                        FGS_API_BEGIN_WITH_FGS,
                    types,
                        apiTypesFound.get(i),
                    timestamps);
                        timestampsFound.get(i));
            }
        }
        }
    }
    }


@@ -192,7 +193,7 @@ public class ForegroundServiceTypeLoggerModule {
        final ArrayList<Integer> apiTypes = convertFgsTypeToApiTypes(record.foregroundServiceType);
        final ArrayList<Integer> apiTypes = convertFgsTypeToApiTypes(record.foregroundServiceType);
        final UidState uidState = mUids.get(uid);
        final UidState uidState = mUids.get(uid);
        if (uidState == null) {
        if (uidState == null) {
            Slog.wtfStack(TAG, "FGS stop call being logged with no start call for UID for UID "
            Slog.w(TAG, "FGS stop call being logged with no start call for UID for UID "
                    + uid
                    + uid
                    + " in package " + record.packageName);
                    + " in package " + record.packageName);
            return;
            return;
@@ -202,7 +203,7 @@ public class ForegroundServiceTypeLoggerModule {
        for (int i = 0, size = apiTypes.size(); i < size; i++) {
        for (int i = 0, size = apiTypes.size(); i < size; i++) {
            final int apiType = apiTypes.get(i);
            final int apiType = apiTypes.get(i);
            if (!uidState.mOpenWithFgsCount.contains(apiType)) {
            if (!uidState.mOpenWithFgsCount.contains(apiType)) {
                Slog.wtfStack(TAG, "Logger should be tracking FGS types correctly for UID " + uid
                Slog.w(TAG, "Logger should be tracking FGS types correctly for UID " + uid
                        + " in package " + record.packageName);
                        + " in package " + record.packageName);
                continue;
                continue;
            }
            }
@@ -231,19 +232,17 @@ public class ForegroundServiceTypeLoggerModule {
            if (runningFgsOfType.size() == 0) {
            if (runningFgsOfType.size() == 0) {
                // there's no more FGS running for this type, just get rid of it
                // there's no more FGS running for this type, just get rid of it
                uidState.mRunningFgs.remove(apiType);
                uidState.mRunningFgs.remove(apiType);
                // but we need to keep track of the timestamp in case an API stops
                uidState.mLastFgsTimeStamp.put(apiType, record.mFgsExitTime);
            }
            }
        }
        }
        if (!apisFound.isEmpty()) {
        if (!apisFound.isEmpty()) {
            // time to log the call
            // time to log the call
            int[] types = new int[apisFound.size()];
            long[] timestamps = new long[apisFound.size()];
            for (int i = 0; i < apisFound.size(); i++) {
            for (int i = 0; i < apisFound.size(); i++) {
                types[i] = apisFound.get(i);
                timestamps[i] = timestampsFound.get(i);
            }
                logFgsApiEvent(record,
                logFgsApiEvent(record,
                        FGS_STATE_CHANGED_API_CALL,
                        FGS_STATE_CHANGED_API_CALL,
                    FGS_API_END_WITH_FGS, types, timestamps);
                        FGS_API_END_WITH_FGS, apisFound.get(i), timestampsFound.get(i));
            }
        }
        }
    }
    }


@@ -303,8 +302,8 @@ public class ForegroundServiceTypeLoggerModule {
        final ArrayMap<ComponentName, ServiceRecord> fgsListMap = uidState.mRunningFgs.get(apiType);
        final ArrayMap<ComponentName, ServiceRecord> fgsListMap = uidState.mRunningFgs.get(apiType);


        // now we get the relevant FGS to log with
        // now we get the relevant FGS to log with
        final int[] apiTypes = {apiType};
        final int apiTypes = apiType;
        final long[] timestamps = {callStart.mTimeStart};
        final long timestamps = callStart.mTimeStart;
        if (uidState.mOpenWithFgsCount.valueAt(openWithFgsIndex) == 1) {
        if (uidState.mOpenWithFgsCount.valueAt(openWithFgsIndex) == 1) {
            for (ServiceRecord record : fgsListMap.values()) {
            for (ServiceRecord record : fgsListMap.values()) {
                logFgsApiEvent(record,
                logFgsApiEvent(record,
@@ -347,13 +346,13 @@ public class ForegroundServiceTypeLoggerModule {
                // we just log that an event happened w/ no
                // we just log that an event happened w/ no
                // FGS associated. This is to avoid dangling
                // FGS associated. This is to avoid dangling
                // events
                // events
                final long[] timestamp = {System.currentTimeMillis()};
                final long timestamp = System.currentTimeMillis();
                final int[] apiTypes = {apiType};
                final int apiTypes = apiType;
                logFgsApiEventWithNoFgs(uid, FGS_API_END_WITHOUT_FGS, apiTypes, timestamp);
                logFgsApiEventWithNoFgs(uid, FGS_API_END_WITHOUT_FGS, apiTypes, timestamp);
                // we should now remove the count, so as to signal that
                // we should now remove the count, so as to signal that
                // there was never an FGS called that can be associated
                // there was never an FGS called that can be associated
                uidState.mOpenWithFgsCount.remove(apiType);
                uidState.mOpenWithFgsCount.remove(apiType);
                return timestamp[0];
                return timestamp;
            }
            }
        }
        }
        // we know now that this call is not coming from an
        // we know now that this call is not coming from an
@@ -392,8 +391,8 @@ public class ForegroundServiceTypeLoggerModule {
            return;
            return;
        }
        }
        final ArrayMap<ComponentName, ServiceRecord> fgsRecords = uidState.mRunningFgs.get(apiType);
        final ArrayMap<ComponentName, ServiceRecord> fgsRecords = uidState.mRunningFgs.get(apiType);
        final int[] apiTypes = {apiType};
        final int apiTypes = apiType;
        final long[] timestamp = {System.currentTimeMillis()};
        final long timestamp = System.currentTimeMillis();
        for (ServiceRecord record : fgsRecords.values()) {
        for (ServiceRecord record : fgsRecords.values()) {
            logFgsApiEvent(record,
            logFgsApiEvent(record,
                    FGS_STATE_CHANGED_API_CALL,
                    FGS_STATE_CHANGED_API_CALL,
@@ -449,7 +448,9 @@ public class ForegroundServiceTypeLoggerModule {
    @VisibleForTesting
    @VisibleForTesting
    public void logFgsApiEvent(ServiceRecord r, int fgsState,
    public void logFgsApiEvent(ServiceRecord r, int fgsState,
            @FgsApiState int apiState,
            @FgsApiState int apiState,
            @ForegroundServiceApiType int[] apiType, long[] timestamp) {
            @ForegroundServiceApiType int apiType, long timestamp) {
        final long apiDurationBeforeFgsStart = r.mFgsEnterTime - timestamp;
        final long apiDurationAfterFgsEnd = timestamp - r.mFgsExitTime;
        FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
        FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                r.appInfo.uid,
                r.appInfo.uid,
                r.shortInstanceName,
                r.shortInstanceName,
@@ -479,7 +480,9 @@ public class ForegroundServiceTypeLoggerModule {
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_CAPABILITY_NONE,
                ActivityManager.PROCESS_CAPABILITY_NONE,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_CAPABILITY_NONE);
                ActivityManager.PROCESS_CAPABILITY_NONE,
                apiDurationBeforeFgsStart,
                apiDurationAfterFgsEnd);
    }
    }


    /**
    /**
@@ -489,7 +492,14 @@ public class ForegroundServiceTypeLoggerModule {
    @VisibleForTesting
    @VisibleForTesting
    public void logFgsApiEventWithNoFgs(int uid,
    public void logFgsApiEventWithNoFgs(int uid,
            @FgsApiState int apiState,
            @FgsApiState int apiState,
            @ForegroundServiceApiType int[] apiType, long[] timestamp) {
            @ForegroundServiceApiType int apiType, long timestamp) {
        long apiDurationAfterFgsEnd = 0;
        UidState uidState = mUids.get(uid);
        if (uidState != null) {
            if (uidState.mLastFgsTimeStamp.contains(apiType)) {
                apiDurationAfterFgsEnd = timestamp - uidState.mLastFgsTimeStamp.get(apiType);
            }
        }
        FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
        FrameworkStatsLog.write(FrameworkStatsLog.FOREGROUND_SERVICE_STATE_CHANGED,
                uid,
                uid,
                null,
                null,
@@ -517,7 +527,9 @@ public class ForegroundServiceTypeLoggerModule {
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_CAPABILITY_NONE,
                ActivityManager.PROCESS_CAPABILITY_NONE,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_STATE_UNKNOWN,
                ActivityManager.PROCESS_CAPABILITY_NONE);
                ActivityManager.PROCESS_CAPABILITY_NONE,
                0,
                apiDurationAfterFgsEnd);
    }
    }


    /**
    /**
+82 −67
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import static com.android.server.am.ForegroundServiceTypeLoggerModule.FGS_STATE_


import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mock;
@@ -41,7 +42,6 @@ import androidx.test.filters.SmallTest;


import org.junit.Before;
import org.junit.Before;
import org.junit.Test;
import org.junit.Test;
import org.mockito.AdditionalMatchers;


/**
/**
 * Test class for {@link ForegroundServiceTypeLoggerModule}.
 * Test class for {@link ForegroundServiceTypeLoggerModule}.
@@ -61,10 +61,10 @@ public class FgsLoggerTest {
        mFgsLogger = spy(logger);
        mFgsLogger = spy(logger);
        doNothing().when(mFgsLogger)
        doNothing().when(mFgsLogger)
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        anyInt(), anyInt(), any(int[].class), any(long[].class));
                        anyInt(), anyInt(), anyInt(), anyLong());
        doNothing().when(mFgsLogger)
        doNothing().when(mFgsLogger)
                .logFgsApiEventWithNoFgs(anyInt(),
                .logFgsApiEventWithNoFgs(anyInt(),
                        anyInt(), any(int[].class), any(long[].class));
                        anyInt(), anyInt(), anyLong());
    }
    }


    @Test
    @Test
@@ -73,10 +73,10 @@ public class FgsLoggerTest {
        record.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
        record.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
        mFgsLogger.logForegroundServiceStart(1, 1, record);
        mFgsLogger.logForegroundServiceStart(1, 1, record);
        mFgsLogger.logForegroundServiceApiEventBegin(1, 1, 1, "aPackageHasNoName");
        mFgsLogger.logForegroundServiceApiEventBegin(1, 1, 1, "aPackageHasNoName");
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);


@@ -85,7 +85,7 @@ public class FgsLoggerTest {
        mFgsLogger.logForegroundServiceStop(1, record);
        mFgsLogger.logForegroundServiceStop(1, record);
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_END_WITH_FGS),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_END_WITH_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
    }
    }


    @Test
    @Test
@@ -97,10 +97,10 @@ public class FgsLoggerTest {
        resetAndVerifyZeroInteractions();
        resetAndVerifyZeroInteractions();


        mFgsLogger.logForegroundServiceStart(1, 1, record);
        mFgsLogger.logForegroundServiceStart(1, 1, record);
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);


@@ -109,7 +109,7 @@ public class FgsLoggerTest {
        mFgsLogger.logForegroundServiceStop(1, record);
        mFgsLogger.logForegroundServiceStop(1, record);
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_END_WITH_FGS),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_END_WITH_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
    }
    }


    @Test
    @Test
@@ -122,12 +122,12 @@ public class FgsLoggerTest {


        resetAndVerifyZeroInteractions();
        resetAndVerifyZeroInteractions();


        int[] expectedTypes = {1};
        int expectedTypes = 1;


        mFgsLogger.logForegroundServiceStart(1, 1, record);
        mFgsLogger.logForegroundServiceStart(1, 1, record);
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
        verify(mFgsLogger).logFgsApiEvent(any(ServiceRecord.class),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                eq(FGS_STATE_CHANGED_API_CALL), eq(FGS_API_BEGIN_WITH_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceStop(1, record);
        mFgsLogger.logForegroundServiceStop(1, record);


@@ -135,7 +135,7 @@ public class FgsLoggerTest {


        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        verify(mFgsLogger).logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
        verify(mFgsLogger).logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                eq(expectedTypes), anyLong());
    }
    }


    @Test
    @Test
@@ -176,15 +176,15 @@ public class FgsLoggerTest {
        // now we should see exactly one call logged
        // now we should see exactly one call logged
        // and this should be the very first call
        // and this should be the very first call
        // we also try to verify the time as being the very first call
        // we also try to verify the time as being the very first call
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        reset(mFgsLogger);
        reset(mFgsLogger);
        // now we do multiple stops
        // now we do multiple stops
        // only the last one should be logged
        // only the last one should be logged
@@ -201,11 +201,11 @@ public class FgsLoggerTest {
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        timeStamp = mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA,
        timeStamp = mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA,
                1, 1);
                1, 1);
        expectedTimestamp[0] = timeStamp;
        expectedTimestamp = timeStamp;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
    }
    }


    @Test
    @Test
@@ -239,15 +239,15 @@ public class FgsLoggerTest {
        // now we should see exactly one call logged
        // now we should see exactly one call logged
        // and this should be the very first call
        // and this should be the very first call
        // we also try to verify the time as being the very first call
        // we also try to verify the time as being the very first call
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        reset(mFgsLogger);
        reset(mFgsLogger);
        // now we do multiple stops
        // now we do multiple stops
        // only the last one should be logged
        // only the last one should be logged
@@ -269,11 +269,11 @@ public class FgsLoggerTest {
                1, 1);
                1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        expectedTimestamp[0] = timeStamp;
        expectedTimestamp = timeStamp;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
    }
    }


    @Test
    @Test
@@ -304,15 +304,15 @@ public class FgsLoggerTest {
        // now we should see exactly one call logged
        // now we should see exactly one call logged
        // and this should be the very first call
        // and this should be the very first call
        // we also try to verify the time as being the very first call
        // we also try to verify the time as being the very first call
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
                "aPackageHasNoName");
                "aPackageHasNoName");
@@ -338,11 +338,11 @@ public class FgsLoggerTest {
                1, 1);
                1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        expectedTimestamp[0] = timeStamp;
        expectedTimestamp = timeStamp;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
    }
    }


    @Test
    @Test
@@ -375,15 +375,15 @@ public class FgsLoggerTest {
        // now we should see exactly one call logged
        // now we should see exactly one call logged
        // and this should be the very first call
        // and this should be the very first call
        // we also try to verify the time as being the very first call
        // we also try to verify the time as being the very first call
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
                "aPackageHasNoName");
                "aPackageHasNoName");
@@ -410,16 +410,16 @@ public class FgsLoggerTest {
        timeStamp = mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);
        timeStamp = mFgsLogger.logForegroundServiceApiEventEnd(1, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1);
        expectedTimestamp[0] = timeStamp;
        expectedTimestamp = timeStamp;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
    }
    }


    @Test
    @Test
    public void testMultipleUid() throws InterruptedException {
    public void testMultipleUid() throws InterruptedException {
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        ServiceRecord record = ServiceRecord.newEmptyInstanceForTest(null);
        ServiceRecord record = ServiceRecord.newEmptyInstanceForTest(null);
        record.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
        record.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
        ActivityManagerService ams = mock(ActivityManagerService.class);
        ActivityManagerService ams = mock(ActivityManagerService.class);
@@ -477,7 +477,7 @@ public class FgsLoggerTest {
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes), any(long[].class));
                        eq(expectedTypes), anyLong());
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
                "aPackageHasNoName");
                "aPackageHasNoName");
@@ -511,16 +511,16 @@ public class FgsLoggerTest {
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 2, 1);
        mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA, 2, 1);
        timeStamp2 = mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA,
        timeStamp2 = mFgsLogger.logForegroundServiceApiEventEnd(FOREGROUND_SERVICE_API_TYPE_CAMERA,
                2, 1);
                2, 1);
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;
        long[] expectedTimestamp2 = {timeStamp2};
        long expectedTimestamp2 = timeStamp2;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(1), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEventWithNoFgs(eq(2), eq(FGS_API_END_WITHOUT_FGS),
                .logFgsApiEventWithNoFgs(eq(2), eq(FGS_API_END_WITHOUT_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp2));
                        eq(expectedTimestamp2));
    }
    }


    @Test
    @Test
@@ -551,15 +551,15 @@ public class FgsLoggerTest {
        // now we should see exactly one call logged
        // now we should see exactly one call logged
        // and this should be the very first call
        // and this should be the very first call
        // we also try to verify the time as being the very first call
        // we also try to verify the time as being the very first call
        int[] expectedTypes = {1};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timeStamp};
        long expectedTimestamp = timeStamp;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        reset(mFgsLogger);
        reset(mFgsLogger);
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
        mFgsLogger.logForegroundServiceApiEventBegin(FOREGROUND_SERVICE_API_TYPE_CAMERA, 1, 1,
                "aPackageHasNoName");
                "aPackageHasNoName");
@@ -590,13 +590,13 @@ public class FgsLoggerTest {
        // now we do multiple stops
        // now we do multiple stops
        // only the last one should be logged
        // only the last one should be logged
        mFgsLogger.logForegroundServiceStop(1, record);
        mFgsLogger.logForegroundServiceStop(1, record);
        expectedTimestamp[0] = timeStamp;
        expectedTimestamp = timeStamp;
        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_END_WITH_FGS),
                        eq(FGS_API_END_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
    }
    }


    @Test
    @Test
@@ -610,16 +610,25 @@ public class FgsLoggerTest {
        long timestamp2 = mFgsLogger.logForegroundServiceApiEventBegin(
        long timestamp2 = mFgsLogger.logForegroundServiceApiEventBegin(
                FOREGROUND_SERVICE_API_TYPE_MICROPHONE,
                FOREGROUND_SERVICE_API_TYPE_MICROPHONE,
                1, 1, "aPackageHasNoName");
                1, 1, "aPackageHasNoName");
        int[] expectedTypes = {1, FOREGROUND_SERVICE_API_TYPE_MICROPHONE};
        int expectedTypes = 1;
        long[] expectedTimestamp = {timestamp1, timestamp2};
        int expectedType2 = FOREGROUND_SERVICE_API_TYPE_MICROPHONE;
        long expectedTimestamp = timestamp1;
        long expectedTimestamp2 = timestamp2;
        mFgsLogger.logForegroundServiceStart(1, 1, record);
        mFgsLogger.logForegroundServiceStart(1, 1, record);


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));

        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_BEGIN_WITH_FGS),
                        eq(expectedType2),
                        eq(expectedTimestamp2));


        reset(mFgsLogger);
        reset(mFgsLogger);
        resetAndVerifyZeroInteractions();
        resetAndVerifyZeroInteractions();
@@ -632,28 +641,34 @@ public class FgsLoggerTest {


        mFgsLogger.logForegroundServiceStop(1, record);
        mFgsLogger.logForegroundServiceStop(1, record);


        expectedTimestamp[0] = timestamp1;
        expectedTimestamp = timestamp1;
        expectedTimestamp[1] = timestamp2;
        expectedTimestamp2 = timestamp2;


        verify(mFgsLogger, times(1))
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_END_WITH_FGS),
                        eq(FGS_API_END_WITH_FGS),
                        AdditionalMatchers.aryEq(expectedTypes),
                        eq(expectedTypes),
                        AdditionalMatchers.aryEq(expectedTimestamp));
                        eq(expectedTimestamp));
        verify(mFgsLogger, times(1))
                .logFgsApiEvent(any(ServiceRecord.class),
                        eq(FGS_STATE_CHANGED_API_CALL),
                        eq(FGS_API_END_WITH_FGS),
                        eq(expectedType2),
                        eq(expectedTimestamp2));


    }
    }


    private void resetAndVerifyZeroInteractions() {
    private void resetAndVerifyZeroInteractions() {
        doNothing().when(mFgsLogger)
        doNothing().when(mFgsLogger)
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        anyInt(), anyInt(), any(int[].class), any(long[].class));
                        anyInt(), anyInt(), anyInt(), anyLong());
        doNothing().when(mFgsLogger)
        doNothing().when(mFgsLogger)
                .logFgsApiEventWithNoFgs(anyInt(), anyInt(), any(int[].class), any(long[].class));
                .logFgsApiEventWithNoFgs(anyInt(), anyInt(), anyInt(), anyLong());
        verify(mFgsLogger, times(0))
        verify(mFgsLogger, times(0))
                .logFgsApiEvent(any(ServiceRecord.class),
                .logFgsApiEvent(any(ServiceRecord.class),
                        anyInt(), anyInt(), any(int[].class), any(long[].class));
                        anyInt(), anyInt(), anyInt(), anyLong());
        verify(mFgsLogger, times(0))
        verify(mFgsLogger, times(0))
                .logFgsApiEventWithNoFgs(anyInt(), anyInt(), any(int[].class), any(long[].class));
                .logFgsApiEventWithNoFgs(anyInt(), anyInt(), anyInt(), anyLong());
    }
    }
}
}