From bc4548b29ef86721ff34c3ca87e6a50c7f84af7b Mon Sep 17 00:00:00 2001 From: Kuan Wang Date: Thu, 1 Dec 2022 17:31:29 +0800 Subject: [PATCH] Add BugReportContentProvider to support new battery usage architecture. Test: make RunSettingsRoboTests + manually Bug: 256123932 Change-Id: I8cc48f5c66e5cbd958bdd73ff8e7d6e555bd9c3b --- AndroidManifest.xml | 5 ++ .../bugreport/BugReportContentProvider.java | 88 ++++++++++++++++++ .../batteryusage/bugreport/LogUtils.java | 72 +++++++++++++++ .../BugReportContentProviderTest.java | 89 +++++++++++++++++++ 4 files changed, 254 insertions(+) create mode 100644 src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java create mode 100644 src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java create mode 100644 tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java diff --git a/AndroidManifest.xml b/AndroidManifest.xml index eb69f6e9ea9..27ecf53204a 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -3031,6 +3031,11 @@ android:authorities="${applicationId}.battery.usage.provider" android:permission="com.android.settings.BATTERY_DATA"/> + + diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java new file mode 100644 index 00000000000..f2cdbbd520d --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProvider.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2022 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.settings.fuelgauge.batteryusage.bugreport; + +import android.content.ContentProvider; +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.net.Uri; +import android.util.Log; + +import com.android.settings.fuelgauge.batteryusage.DatabaseUtils; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** Provides debug information in the bugreports when device is dumpping. */ +public final class BugReportContentProvider extends ContentProvider { + private static final String TAG = "BugReportContentProvider"; + + @Override + public boolean onCreate() { + return true; + } + + @Override + public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + final Context context = getContext(); + if (context == null) { + Log.w(TAG, "failed to dump BatteryUsage state: null context"); + return; + } + if (DatabaseUtils.isWorkProfile(context)) { + Log.w(TAG, "ignore battery usage states dump in the work profile"); + return; + } + writer.println("dump BatteryUsage states:"); + LogUtils.dumpUsageDatabaseHist(context, writer); + } + + @Override + public Cursor query( + Uri uri, + String[] projection, + String selection, + String[] selectionArgs, + String sortOrder) { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public String getType(Uri uri) { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public Uri insert(Uri uri, ContentValues values) { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public int delete(Uri uri, String selection, String[] selectionArgs) { + throw new UnsupportedOperationException("unsupported!"); + } + + @Override + public int update( + Uri uri, + ContentValues values, + String selection, + String[] selectionArgs) { + throw new UnsupportedOperationException("unsupported!"); + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java new file mode 100644 index 00000000000..327957ddef3 --- /dev/null +++ b/src/com/android/settings/fuelgauge/batteryusage/bugreport/LogUtils.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2022 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.settings.fuelgauge.batteryusage.bugreport; + +import android.content.Context; +import android.util.Log; + +import com.android.settings.fuelgauge.batteryusage.db.BatteryState; +import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDao; +import com.android.settings.fuelgauge.batteryusage.db.BatteryStateDatabase; + +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.time.Clock; +import java.time.Duration; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +/** A utility class to aggregate and provide required log data. */ +public final class LogUtils { + private static final String TAG = "LogUtils"; + private static final Duration DUMP_TIME_OFFSET = Duration.ofHours(24); + private static final Duration DUMP_TIME_OFFSET_FOR_ENTRY = Duration.ofHours(4); + + @SuppressWarnings("JavaUtilDate") + static void dumpUsageDatabaseHist(Context context, PrintWriter writer) { + final BatteryStateDao dao = + BatteryStateDatabase + .getInstance(context.getApplicationContext()) + .batteryStateDao(); + final long timeOffset = + Clock.systemUTC().millis() - DUMP_TIME_OFFSET.toMillis(); + // Gets all distinct timestamps. + final List timestamps = dao.getDistinctTimestamps(timeOffset); + final int distinctCount = timestamps.size(); + writer.println("\n\tDatabaseHistory:"); + writer.println("distinct timestamp count:" + distinctCount); + Log.w(TAG, "distinct timestamp count:" + distinctCount); + if (distinctCount == 0) { + return; + } + // Dumps all distinct timestamps. + final SimpleDateFormat formatter = + new SimpleDateFormat("MMM dd, HH:mm:ss", Locale.US); + timestamps.forEach(timestamp -> { + final String formattedTimestamp = formatter.format(new Date(timestamp)); + writer.println("\t" + formattedTimestamp); + Log.w(TAG, "\t" + formattedTimestamp); + }); + + final List stateList = dao.getAllAfter( + Clock.systemUTC().millis() - DUMP_TIME_OFFSET_FOR_ENTRY.toMillis()); + stateList.stream().forEach(state -> writer.println(state)); + } + + private LogUtils() {} +} diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java new file mode 100644 index 00000000000..87e253f6730 --- /dev/null +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/bugreport/BugReportContentProviderTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2022 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.settings.fuelgauge.batteryusage.bugreport; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; + +import androidx.test.core.app.ApplicationProvider; + +import com.android.settings.testutils.BatteryTestUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.io.StringWriter; + +/** Tests of {@link BugReportContentProvider}. */ +@RunWith(RobolectricTestRunner.class) +public final class BugReportContentProviderTest { + private static final String PACKAGE_NAME1 = "com.android.settings"; + private static final String PACKAGE_NAME2 = "com.android.systemui"; + + private Context mContext; + private PrintWriter mPrintWriter; + private StringWriter mStringWriter; + private BugReportContentProvider mBugReportContentProvider; + + @Before + public void setUp() { + mStringWriter = new StringWriter(); + mPrintWriter = new PrintWriter(mStringWriter); + mContext = ApplicationProvider.getApplicationContext(); + mBugReportContentProvider = new BugReportContentProvider(); + mBugReportContentProvider.attachInfo(mContext, /*info=*/ null); + // Inserts fake data into database for testing. + BatteryTestUtils.setUpBatteryStateDatabase(mContext); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, System.currentTimeMillis(), PACKAGE_NAME1); + BatteryTestUtils.insertDataToBatteryStateDatabase( + mContext, System.currentTimeMillis(), PACKAGE_NAME2); + } + + @Test + public void dump_nullContext_notDumpsBatteryUsageData() { + mBugReportContentProvider = new BugReportContentProvider(); + mBugReportContentProvider.attachInfo(/*context=*/ null, /*info=*/ null); + + mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {}); + + assertThat(mStringWriter.toString()).isEmpty(); + } + + @Test + public void dump_inWorkProfileMode_notDumpsBatteryUsageData() { + BatteryTestUtils.setWorkProfile(mContext); + mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {}); + assertThat(mStringWriter.toString()).isEmpty(); + } + + @Test + public void dump_dumpsBatteryUsageHistory() { + mBugReportContentProvider.dump(FileDescriptor.out, mPrintWriter, new String[] {}); + + String dumpContent = mStringWriter.toString(); + assertThat(dumpContent).contains("DatabaseHistory"); + assertThat(dumpContent).contains(PACKAGE_NAME1); + assertThat(dumpContent).contains(PACKAGE_NAME2); + assertThat(dumpContent).contains("distinct timestamp count:2"); + } +}