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

Commit ed670559 authored by Hyundo Moon's avatar Hyundo Moon Committed by Gerrit Code Review
Browse files

Merge "Add ContentProfileErrorReportUtils" into main

parents c71e40ae 92abd165
Loading
Loading
Loading
Loading
+85 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.bluetooth.content_profiles;

import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothProtoEnums;
import android.os.SystemClock;
import android.util.Log;

import com.android.bluetooth.BluetoothStatsLog;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.VisibleForTesting;

/**
 * Utility method to report exceptions and error/warn logs in content profiles. Will be no-op if
 * {@link Flags#contentProfilesErrorsMetrics()} is not enabled.
 */
public class ContentProfileErrorReportUtils {
    private static final String TAG = ContentProfileErrorReportUtils.class.getSimpleName();

    /* Minimum period between two error reports */
    @VisibleForTesting static final long MIN_PERIOD_BETWEEN_TWO_ERROR_REPORTS_MILLIS = 1_000;

    /* Whether reporting is enabled by flags */
    @VisibleForTesting static boolean sEnabled = Flags.contentProfilesErrorsMetrics();

    @VisibleForTesting static long sLastReportTime = 0;

    /**
     * Report error by writing BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED atom. A
     * report will be skipped if not enough time has passed from the last report.
     *
     * @param profile One of: {@link BluetoothProfile#PBAP}, {@link BluetoothProfile#MAP}, {@link
     *     BluetoothProfile#OPP}
     * @param fileNameEnum File name enum which is declared in {@link BluetoothProtoEnums}
     * @param type One of the following: {@link
     *     BluetoothStatsLog#BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__EXCEPTION}, {@link
     *     BluetoothStatsLog#BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_ERROR}, {@link
     *     BluetoothStatsLog#BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED__TYPE__LOG_WARN}
     * @param tag A tag which represents the code location of this error. The values are managed per
     *     each java file.
     */
    public static synchronized void report(int profile, int fileNameEnum, int type, int tag) {
        if (!sEnabled) {
            return;
        }

        if (isTooFrequentReport()) {
            Log.w(
                    TAG,
                    "Skipping reporting this error to prevent flooding."
                            + " fileNameEnum="
                            + fileNameEnum
                            + ", tag="
                            + tag);
            return;
        }

        BluetoothStatsLog.write(
                BluetoothStatsLog.BLUETOOTH_CONTENT_PROFILE_ERROR_REPORTED,
                profile,
                fileNameEnum,
                type,
                tag);
        sLastReportTime = SystemClock.uptimeMillis();
    }

    private static boolean isTooFrequentReport() {
        return SystemClock.uptimeMillis() - sLastReportTime
                < MIN_PERIOD_BETWEEN_TWO_ERROR_REPORTS_MILLIS;
    }
}
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ java_defaults {
        "androidx.test.ext.truth",
        "androidx.test.rules",
        "androidx.test.uiautomator_uiautomator",
        "flag-junit",
        "framework-bluetooth-pre-jarjar",
        "frameworks-base-testutils",
        "gson",
+81 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.bluetooth.content_profiles;

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

import android.os.SystemClock;
import android.platform.test.flag.junit.SetFlagsRule;

import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;

import com.android.bluetooth.flags.Flags;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

@SmallTest
@RunWith(AndroidJUnit4.class)
public class ContentProfileErrorReportUtilsTest {

    @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();

    @Test
    public void noOpWhenFlagIsDisabled() {
        mSetFlagsRule.disableFlags(Flags.FLAG_CONTENT_PROFILES_ERRORS_METRICS);
        long previousReportTimeMillis = ContentProfileErrorReportUtils.sLastReportTime;

        ContentProfileErrorReportUtils.report(0, 0, 0, 0);

        // The last report time should not be changed.
        assertThat(ContentProfileErrorReportUtils.sLastReportTime)
                .isEqualTo(previousReportTimeMillis);
    }

    @Test
    public void tooFrequentErrorReportIsSkipped() {
        mSetFlagsRule.enableFlags(Flags.FLAG_CONTENT_PROFILES_ERRORS_METRICS);
        // Set the last report time to the current time.
        long lastReportTimeMillisToSet = SystemClock.uptimeMillis();
        ContentProfileErrorReportUtils.sLastReportTime = lastReportTimeMillisToSet;

        ContentProfileErrorReportUtils.report(0, 0, 0, 0);

        // The last report time should not be changed.
        assertThat(ContentProfileErrorReportUtils.sLastReportTime)
                .isEqualTo(lastReportTimeMillisToSet);
    }

    @Test
    public void successfulReport() {
        mSetFlagsRule.enableFlags(Flags.FLAG_CONTENT_PROFILES_ERRORS_METRICS);
        // Set the last report time to much earlier than the current time.
        long lastReportTimeMillisToSet =
                SystemClock.uptimeMillis()
                        - (ContentProfileErrorReportUtils
                                        .MIN_PERIOD_BETWEEN_TWO_ERROR_REPORTS_MILLIS
                                * 2);
        ContentProfileErrorReportUtils.sLastReportTime = lastReportTimeMillisToSet;

        ContentProfileErrorReportUtils.report(0, 0, 0, 0);

        // After the successful report, the last report time should be changed.
        assertThat(ContentProfileErrorReportUtils.sLastReportTime)
                .isGreaterThan(lastReportTimeMillisToSet);
    }
}