Merge "Implement pull logging for Notification Memory" into tm-qpr-dev
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index ec2e340..48a68be 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -123,7 +123,7 @@
@SysUISingleton
@QSLog
public static LogBuffer provideQuickSettingsLogBuffer(LogBufferFactory factory) {
- return factory.create("QSLog", 500 /* maxSize */, false /* systrace */);
+ return factory.create("QSLog", 700 /* maxSize */, false /* systrace */);
}
/** Provides a logging buffer for {@link com.android.systemui.broadcast.BroadcastDispatcher} */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 8ceee1a..7523d6e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -11,7 +11,6 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -31,6 +30,7 @@
import com.android.systemui.plugins.qs.QSTile;
import com.android.systemui.qs.QSPanel.QSTileLayout;
import com.android.systemui.qs.QSPanelControllerBase.TileRecord;
+import com.android.systemui.qs.logging.QSLogger;
import java.util.ArrayList;
import java.util.List;
@@ -38,11 +38,9 @@
public class PagedTileLayout extends ViewPager implements QSTileLayout {
- private static final boolean DEBUG = false;
private static final String CURRENT_PAGE = "current_page";
private static final int NO_PAGE = -1;
- private static final String TAG = "PagedTileLayout";
private static final int REVEAL_SCROLL_DURATION_MILLIS = 750;
private static final float BOUNCE_ANIMATION_TENSION = 1.3f;
private static final long BOUNCE_ANIMATION_DURATION = 450L;
@@ -55,6 +53,7 @@
private final ArrayList<TileRecord> mTiles = new ArrayList<>();
private final ArrayList<TileLayout> mPages = new ArrayList<>();
+ private QSLogger mLogger;
@Nullable
private PageIndicator mPageIndicator;
private float mPageIndicatorPosition;
@@ -146,9 +145,15 @@
}
if (mLayoutOrientation != newConfig.orientation) {
mLayoutOrientation = newConfig.orientation;
- mDistributeTiles = true;
+ forceTilesRedistribution("orientation changed to " + mLayoutOrientation);
setCurrentItem(0, false);
mPageToRestore = 0;
+ } else {
+ // logging in case we missed redistribution because orientation was not changed
+ // while configuration changed, can be removed after b/255208946 is fixed
+ mLogger.d(
+ "Orientation didn't change, tiles might be not redistributed, new config",
+ newConfig);
}
}
@@ -226,7 +231,7 @@
// Keep on drawing until the animation has finished.
postInvalidateOnAnimation();
} catch (NullPointerException e) {
- Log.e(TAG, "FakeDragBy called before begin", e);
+ mLogger.logException("FakeDragBy called before begin", e);
// If we were trying to fake drag, it means we just added a new tile to the last
// page, so animate there.
final int lastPageNumber = mPages.size() - 1;
@@ -246,7 +251,7 @@
super.endFakeDrag();
} catch (NullPointerException e) {
// Not sure what's going on. Let's log it
- Log.e(TAG, "endFakeDrag called without velocityTracker", e);
+ mLogger.logException("endFakeDrag called without velocityTracker", e);
}
}
@@ -304,14 +309,14 @@
@Override
public void addTile(TileRecord tile) {
mTiles.add(tile);
- mDistributeTiles = true;
+ forceTilesRedistribution("adding new tile");
requestLayout();
}
@Override
public void removeTile(TileRecord tile) {
if (mTiles.remove(tile)) {
- mDistributeTiles = true;
+ forceTilesRedistribution("removing tile");
requestLayout();
}
}
@@ -367,19 +372,11 @@
final int tilesPerPageCount = mPages.get(0).maxTiles();
int index = 0;
final int totalTilesCount = mTiles.size();
- if (DEBUG) {
- Log.d(TAG, "Distributing tiles: "
- + "[tilesPerPageCount=" + tilesPerPageCount + "]"
- + "[totalTilesCount=" + totalTilesCount + "]"
- );
- }
+ mLogger.logTileDistributionInProgress(tilesPerPageCount, totalTilesCount);
for (int i = 0; i < totalTilesCount; i++) {
TileRecord tile = mTiles.get(i);
if (mPages.get(index).mRecords.size() == tilesPerPageCount) index++;
- if (DEBUG) {
- Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
- + index);
- }
+ mLogger.logTileDistributed(tile.tile.getClass().getSimpleName(), index);
mPages.get(index).addTile(tile);
}
}
@@ -394,11 +391,11 @@
return;
}
while (mPages.size() < numPages) {
- if (DEBUG) Log.d(TAG, "Adding page");
+ mLogger.d("Adding new page");
mPages.add(createTileLayout());
}
while (mPages.size() > numPages) {
- if (DEBUG) Log.d(TAG, "Removing page");
+ mLogger.d("Removing page");
mPages.remove(mPages.size() - 1);
}
mPageIndicator.setNumPages(mPages.size());
@@ -417,8 +414,12 @@
changed |= mPages.get(i).updateResources();
}
if (changed) {
- mDistributeTiles = true;
+ forceTilesRedistribution("resources in pages changed");
requestLayout();
+ } else {
+ // logging in case we missed redistribution because number of column in updateResources
+ // was not changed, can be removed after b/255208946 is fixed
+ mLogger.d("resource in pages didn't change, tiles might be not redistributed");
}
return changed;
}
@@ -430,7 +431,7 @@
for (int i = 0; i < mPages.size(); i++) {
if (mPages.get(i).setMinRows(minRows)) {
changed = true;
- mDistributeTiles = true;
+ forceTilesRedistribution("minRows changed in page");
}
}
return changed;
@@ -443,7 +444,7 @@
for (int i = 0; i < mPages.size(); i++) {
if (mPages.get(i).setMaxColumns(maxColumns)) {
changed = true;
- mDistributeTiles = true;
+ forceTilesRedistribution("maxColumns in pages changed");
}
}
return changed;
@@ -710,14 +711,14 @@
private final PagerAdapter mAdapter = new PagerAdapter() {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
- if (DEBUG) Log.d(TAG, "Destantiating " + position);
+ mLogger.d("Destantiating page at", position);
container.removeView((View) object);
updateListening();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
- if (DEBUG) Log.d(TAG, "Instantiating " + position);
+ mLogger.d("Instantiating page at", position);
if (isLayoutRtl()) {
position = mPages.size() - 1 - position;
}
@@ -745,10 +746,15 @@
* Force all tiles to be redistributed across pages.
* Should be called when one of the following changes: rows, columns, number of tiles.
*/
- public void forceTilesRedistribution() {
+ public void forceTilesRedistribution(String reason) {
+ mLogger.d("forcing tile redistribution across pages, reason", reason);
mDistributeTiles = true;
}
+ public void setLogger(QSLogger qsLogger) {
+ mLogger = qsLogger;
+ }
+
public interface PageListener {
int INVALID_PAGE = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 6517ff3..7067c220 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -43,6 +43,7 @@
import com.android.internal.widget.RemeasuringLinearLayout;
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.logging.QSLogger;
import com.android.systemui.settings.brightness.BrightnessSliderController;
import com.android.systemui.tuner.TunerService;
import com.android.systemui.tuner.TunerService.Tunable;
@@ -106,6 +107,7 @@
private ViewGroup mMediaHostView;
private boolean mShouldMoveMediaOnExpansion = true;
private boolean mUsingCombinedHeaders = false;
+ private QSLogger mQsLogger;
public QSPanel(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -122,7 +124,8 @@
}
- void initialize() {
+ void initialize(QSLogger qsLogger) {
+ mQsLogger = qsLogger;
mTileLayout = getOrCreateTileLayout();
if (mUsingMediaPlayer) {
@@ -206,6 +209,7 @@
if (mTileLayout == null) {
mTileLayout = (QSTileLayout) LayoutInflater.from(mContext)
.inflate(R.layout.qs_paged_tile_layout, this, false);
+ mTileLayout.setLogger(mQsLogger);
mTileLayout.setSquishinessFraction(mSquishinessFraction);
}
return mTileLayout;
@@ -735,6 +739,8 @@
default void setExpansion(float expansion, float proposedTranslation) {}
int getNumVisibleTiles();
+
+ default void setLogger(QSLogger qsLogger) { }
}
interface OnConfigurationChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
index b2ca6b7..cabe1da 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelController.java
@@ -122,9 +122,8 @@
}
switchTileLayout(true);
mBrightnessMirrorHandler.onQsPanelAttached();
-
- ((PagedTileLayout) mView.getOrCreateTileLayout())
- .setOnTouchListener(mTileLayoutTouchListener);
+ PagedTileLayout pagedTileLayout= ((PagedTileLayout) mView.getOrCreateTileLayout());
+ pagedTileLayout.setOnTouchListener(mTileLayoutTouchListener);
}
@Override
@@ -150,7 +149,8 @@
@Override
protected void onSplitShadeChanged() {
- ((PagedTileLayout) mView.getOrCreateTileLayout()).forceTilesRedistribution();
+ ((PagedTileLayout) mView.getOrCreateTileLayout())
+ .forceTilesRedistribution("Split shade state changed");
}
/** */
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index 60d2c17..7bb672c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -70,7 +70,7 @@
protected final MediaHost mMediaHost;
protected final MetricsLogger mMetricsLogger;
private final UiEventLogger mUiEventLogger;
- private final QSLogger mQSLogger;
+ protected final QSLogger mQSLogger;
private final DumpManager mDumpManager;
protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
protected boolean mShouldUseSplitNotificationShade;
@@ -152,7 +152,7 @@
@Override
protected void onInit() {
- mView.initialize();
+ mView.initialize(mQSLogger);
mQSLogger.logAllTilesChangeListening(mView.isListening(), mView.getDumpableTag(), "");
}
@@ -430,6 +430,7 @@
pw.println(" horizontal layout: " + mUsingHorizontalLayout);
pw.println(" last orientation: " + mLastOrientation);
}
+ pw.println(" mShouldUseSplitNotificationShade: " + mShouldUseSplitNotificationShade);
}
public QSPanel.QSTileLayout getTileLayout() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
index 9f6317f..d682853f5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/logging/QSLogger.kt
@@ -21,10 +21,13 @@
import com.android.systemui.plugins.log.LogBuffer
import com.android.systemui.plugins.log.LogLevel
import com.android.systemui.plugins.log.LogLevel.DEBUG
+import com.android.systemui.plugins.log.LogLevel.ERROR
import com.android.systemui.plugins.log.LogLevel.VERBOSE
+import com.android.systemui.plugins.log.LogLevel.WARNING
import com.android.systemui.plugins.log.LogMessage
import com.android.systemui.plugins.qs.QSTile
import com.android.systemui.statusbar.StatusBarState
+import com.google.errorprone.annotations.CompileTimeConstant
import javax.inject.Inject
private const val TAG = "QSLog"
@@ -33,6 +36,26 @@
@QSLog private val buffer: LogBuffer
) {
+ fun d(@CompileTimeConstant msg: String) = buffer.log(TAG, DEBUG, msg)
+
+ fun e(@CompileTimeConstant msg: String) = buffer.log(TAG, ERROR, msg)
+
+ fun v(@CompileTimeConstant msg: String) = buffer.log(TAG, VERBOSE, msg)
+
+ fun w(@CompileTimeConstant msg: String) = buffer.log(TAG, WARNING, msg)
+
+ fun logException(@CompileTimeConstant logMsg: String, ex: Exception) {
+ buffer.log(TAG, ERROR, {}, { logMsg }, exception = ex)
+ }
+
+ fun v(@CompileTimeConstant msg: String, arg: Any) {
+ buffer.log(TAG, VERBOSE, { str1 = arg.toString() }, { "$msg: $str1" })
+ }
+
+ fun d(@CompileTimeConstant msg: String, arg: Any) {
+ buffer.log(TAG, DEBUG, { str1 = arg.toString() }, { "$msg: $str1" })
+ }
+
fun logTileAdded(tileSpec: String) {
log(DEBUG, {
str1 = tileSpec
@@ -236,6 +259,24 @@
})
}
+ fun logTileDistributionInProgress(tilesPerPageCount: Int, totalTilesCount: Int) {
+ log(DEBUG, {
+ int1 = tilesPerPageCount
+ int2 = totalTilesCount
+ }, {
+ "Distributing tiles: [tilesPerPageCount=$int1] [totalTilesCount=$int2]"
+ })
+ }
+
+ fun logTileDistributed(tileName: String, pageIndex: Int) {
+ log(DEBUG, {
+ str1 = tileName
+ int1 = pageIndex
+ }, {
+ "Adding $str1 to page number $int1"
+ })
+ }
+
private fun toStateString(state: Int): String {
return when (state) {
Tile.STATE_ACTIVE -> "active"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
index 0eb0000..dc9b416 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/Roundable.kt
@@ -306,9 +306,12 @@
*/
class RoundableState(
internal val targetView: View,
- roundable: Roundable,
- internal val maxRadius: Float,
+ private val roundable: Roundable,
+ maxRadius: Float,
) {
+ internal var maxRadius = maxRadius
+ private set
+
/** Animatable for top roundness */
private val topAnimatable = topAnimatable(roundable)
@@ -356,6 +359,13 @@
PropertyAnimator.setProperty(targetView, bottomAnimatable, value, DURATION, animated)
}
+ fun setMaxRadius(radius: Float) {
+ if (maxRadius != radius) {
+ maxRadius = radius
+ roundable.applyRoundnessAndInvalidate()
+ }
+ }
+
fun debugString() = buildString {
append("TargetView: ${targetView.hashCode()} ")
append("Top: $topRoundness ")
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 0213b96..2041245 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -214,7 +214,11 @@
} else {
maxRadius = res.getDimensionPixelSize(R.dimen.notification_corner_radius);
}
- mRoundableState = new RoundableState(this, this, maxRadius);
+ if (mRoundableState == null) {
+ mRoundableState = new RoundableState(this, this, maxRadius);
+ } else {
+ mRoundableState.setMaxRadius(maxRadius);
+ }
setClipToOutline(mAlwaysRoundBothCorners);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index caf8321..5058373 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -226,7 +226,8 @@
+ " " + mockTileViewString + "\n"
+ " media bounds: null\n"
+ " horizontal layout: false\n"
- + " last orientation: 0\n";
+ + " last orientation: 0\n"
+ + " mShouldUseSplitNotificationShade: false\n";
assertEquals(expected, w.getBuffer().toString());
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
index 5e082f6..6cf642c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerTest.kt
@@ -135,10 +135,10 @@
fun configurationChange_onlySplitShadeConfigChanges_tileAreRedistributed() {
testableResources.addOverride(R.bool.config_use_split_notification_shade, false)
controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
- verify(pagedTileLayout, never()).forceTilesRedistribution()
+ verify(pagedTileLayout, never()).forceTilesRedistribution(any())
testableResources.addOverride(R.bool.config_use_split_notification_shade, true)
controller.mOnConfigurationChangedListener.onConfigurationChange(configuration)
- verify(pagedTileLayout).forceTilesRedistribution()
+ verify(pagedTileLayout).forceTilesRedistribution("Split shade state changed")
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 7c930b1..d52b296 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -27,6 +27,7 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSIconViewImpl
import com.android.systemui.qs.tileimpl.QSTileViewImpl
import com.google.common.truth.Truth.assertThat
@@ -34,6 +35,7 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -42,6 +44,9 @@
@RunWithLooper
@SmallTest
class QSPanelTest : SysuiTestCase() {
+
+ @Mock private lateinit var qsLogger: QSLogger
+
private lateinit var testableLooper: TestableLooper
private lateinit var qsPanel: QSPanel
@@ -57,7 +62,7 @@
qsPanel = QSPanel(context, null)
qsPanel.mUsingMediaPlayer = true
- qsPanel.initialize()
+ qsPanel.initialize(qsLogger)
// QSPanel inflates a footer inside of it, mocking it here
footer = LinearLayout(context).apply { id = R.id.qs_footer }
qsPanel.addView(footer, MATCH_PARENT, 100)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
index a6a584d..3fba393 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QuickQSPanelTest.kt
@@ -7,10 +7,12 @@
import android.widget.FrameLayout
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.qs.logging.QSLogger
import com.google.common.truth.Truth
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@@ -19,6 +21,8 @@
@SmallTest
class QuickQSPanelTest : SysuiTestCase() {
+ @Mock private lateinit var qsLogger: QSLogger
+
private lateinit var testableLooper: TestableLooper
private lateinit var quickQSPanel: QuickQSPanel
@@ -32,7 +36,7 @@
testableLooper.runWithLooper {
quickQSPanel = QuickQSPanel(mContext, null)
- quickQSPanel.initialize()
+ quickQSPanel.initialize(qsLogger)
quickQSPanel.onFinishInflate()
// Provides a parent with non-zero size for QSPanel
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
index 5f57695..3f61af0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ActivatableNotificationViewTest.kt
@@ -26,6 +26,7 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.notification.FakeShadowView
import com.android.systemui.statusbar.notification.NotificationUtils
+import com.android.systemui.statusbar.notification.SourceType
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -83,4 +84,17 @@
mView.updateBackgroundColors()
assertThat(mView.currentBackgroundTint).isEqualTo(mNormalColor)
}
+
+ @Test
+ fun roundnessShouldBeTheSame_after_onDensityOrFontScaleChanged() {
+ val roundableState = mView.roundableState
+ assertThat(mView.topRoundness).isEqualTo(0f)
+ mView.requestTopRoundness(1f, SourceType.from(""))
+ assertThat(mView.topRoundness).isEqualTo(1f)
+
+ mView.onDensityOrFontScaleChanged()
+
+ assertThat(mView.topRoundness).isEqualTo(1f)
+ assertThat(mView.roundableState.hashCode()).isEqualTo(roundableState.hashCode())
+ }
}
\ No newline at end of file
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
index b9d2ae6..3a8b8cc 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -19,13 +19,13 @@
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.service.voice.HotwordAudioStream.KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION;
-import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__EMPTY_AUDIO_STREAM_LIST;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ILLEGAL_COPY_BUFFER_SIZE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED;
import static com.android.server.voiceinteraction.HotwordDetectionConnection.DEBUG;
import android.annotation.NonNull;
@@ -98,14 +98,17 @@
throws IOException {
List<HotwordAudioStream> audioStreams = result.getAudioStreams();
if (audioStreams.isEmpty()) {
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST,
- mVoiceInteractorUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__EMPTY_AUDIO_STREAM_LIST,
+ mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
+ /* streamCount= */ 0);
return result;
}
+ final int audioStreamCount = audioStreams.size();
List<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size());
List<CopyTaskInfo> copyTaskInfos = new ArrayList<>(audioStreams.size());
+ int totalMetadataBundleSizeBytes = 0;
for (HotwordAudioStream audioStream : audioStreams) {
ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe();
ParcelFileDescriptor clientAudioSource = clientPipe[0];
@@ -117,12 +120,14 @@
int copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES;
PersistableBundle metadata = audioStream.getMetadata();
+ totalMetadataBundleSizeBytes += HotwordDetectedResult.getParcelableSize(metadata);
if (metadata.containsKey(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES)) {
copyBufferLength = metadata.getInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, -1);
if (copyBufferLength < 1 || copyBufferLength > MAX_COPY_BUFFER_LENGTH_BYTES) {
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE,
- mVoiceInteractorUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ILLEGAL_COPY_BUFFER_SIZE,
+ mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
+ audioStreamCount);
Slog.w(TAG, "Attempted to set an invalid copy buffer length ("
+ copyBufferLength + ") for: " + audioStream);
copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES;
@@ -139,7 +144,9 @@
}
String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result);
- mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos));
+ mExecutorService.execute(
+ new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos,
+ totalMetadataBundleSizeBytes));
return result.buildUpon().setAudioStreams(newAudioStreams).build();
}
@@ -159,11 +166,14 @@
private class HotwordDetectedResultCopyTask implements Runnable {
private final String mResultTaskId;
private final List<CopyTaskInfo> mCopyTaskInfos;
+ private final int mTotalMetadataSizeBytes;
private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
- HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos) {
+ HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos,
+ int totalMetadataSizeBytes) {
mResultTaskId = resultTaskId;
mCopyTaskInfos = copyTaskInfos;
+ mTotalMetadataSizeBytes = totalMetadataSizeBytes;
}
@Override
@@ -183,19 +193,38 @@
mVoiceInteractorUid, mVoiceInteractorPackageName,
mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) {
try {
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START,
- mVoiceInteractorUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__STARTED,
+ mVoiceInteractorUid, /* streamSizeBytes= */ 0, mTotalMetadataSizeBytes,
+ size);
// TODO(b/244599891): Set timeout, close after inactivity
mExecutorService.invokeAll(tasks);
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END,
- mVoiceInteractorUid);
+
+ int totalStreamSizeBytes = 0;
+ for (SingleAudioStreamCopyTask task : tasks) {
+ totalStreamSizeBytes += task.mTotalCopiedBytes;
+ }
+
+ Slog.i(TAG, mResultTaskId + ": Task was completed. Total bytes streamed: "
+ + totalStreamSizeBytes + ", total metadata bundle size bytes: "
+ + mTotalMetadataSizeBytes);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__ENDED,
+ mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+ size);
} catch (InterruptedException e) {
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION,
- mVoiceInteractorUid);
- Slog.e(TAG, mResultTaskId + ": Task was interrupted", e);
+ int totalStreamSizeBytes = 0;
+ for (SingleAudioStreamCopyTask task : tasks) {
+ totalStreamSizeBytes += task.mTotalCopiedBytes;
+ }
+
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__INTERRUPTED_EXCEPTION,
+ mVoiceInteractorUid, totalStreamSizeBytes, mTotalMetadataSizeBytes,
+ size);
+ Slog.e(TAG, mResultTaskId + ": Task was interrupted. Total bytes streamed: "
+ + totalStreamSizeBytes + ", total metadata bundle size bytes: "
+ + mTotalMetadataSizeBytes);
bestEffortPropagateError(e.getMessage());
} finally {
mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
@@ -203,9 +232,10 @@
mVoiceInteractorAttributionTag);
}
} else {
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION,
- mVoiceInteractorUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__NO_PERMISSION,
+ mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
+ size);
bestEffortPropagateError(
"Failed to obtain RECORD_AUDIO_HOTWORD permission for voice interactor with"
+ " uid=" + mVoiceInteractorUid
@@ -220,9 +250,10 @@
copyTaskInfo.mSource.closeWithError(errorMessage);
copyTaskInfo.mSink.closeWithError(errorMessage);
}
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM,
- mVoiceInteractorUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM,
+ mVoiceInteractorUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
+ mCopyTaskInfos.size());
} catch (IOException e) {
Slog.e(TAG, mResultTaskId + ": Failed to propagate error", e);
}
@@ -237,6 +268,8 @@
private final int mDetectorType;
private final int mUid;
+ private volatile int mTotalCopiedBytes = 0;
+
SingleAudioStreamCopyTask(String streamTaskId, ParcelFileDescriptor audioSource,
ParcelFileDescriptor audioSink, int copyBufferLength, int detectorType, int uid) {
mStreamTaskId = streamTaskId;
@@ -281,6 +314,7 @@
Arrays.copyOfRange(buffer, 0, 20)));
}
fos.write(buffer, 0, bytesRead);
+ mTotalCopiedBytes += bytesRead;
}
// TODO(b/244599891): Close PFDs after inactivity
}
@@ -288,8 +322,10 @@
mAudioSource.closeWithError(e.getMessage());
mAudioSink.closeWithError(e.getMessage());
Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e);
- HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
- HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, mUid);
+ HotwordMetricsLogger.writeAudioEgressEvent(mDetectorType,
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__EVENT__CLOSE_ERROR_FROM_SYSTEM,
+ mUid, /* streamSizeBytes= */ 0, /* bundleSizeBytes= */ 0,
+ /* streamCount= */ 0);
} finally {
if (fis != null) {
fis.close();
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
index 61c18be..c35d90f 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordMetricsLogger.java
@@ -16,6 +16,9 @@
package com.android.server.voiceinteraction;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
@@ -47,6 +50,12 @@
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
private static final int METRICS_INIT_NORMAL_DETECTOR =
HOTWORD_DETECTION_SERVICE_INIT_RESULT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
+ private static final int AUDIO_EGRESS_DSP_DETECTOR =
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_DSP;
+ private static final int AUDIO_EGRESS_SOFTWARE_DETECTOR =
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__TRUSTED_DETECTOR_SOFTWARE;
+ private static final int AUDIO_EGRESS_NORMAL_DETECTOR =
+ HOTWORD_AUDIO_EGRESS_EVENT_REPORTED__DETECTOR_TYPE__NORMAL_DETECTOR;
private HotwordMetricsLogger() {
// Class only contains static utility functions, and should not be instantiated
@@ -97,6 +106,16 @@
metricsDetectorType, event, uid);
}
+ /**
+ * Logs information related to hotword audio egress events.
+ */
+ public static void writeAudioEgressEvent(int detectorType, int event, int uid,
+ int streamSizeBytes, int bundleSizeBytes, int streamCount) {
+ int metricsDetectorType = getAudioEgressDetectorType(detectorType);
+ FrameworkStatsLog.write(FrameworkStatsLog.HOTWORD_AUDIO_EGRESS_EVENT_REPORTED,
+ metricsDetectorType, event, uid, streamSizeBytes, bundleSizeBytes, streamCount);
+ }
+
private static int getCreateMetricsDetectorType(int detectorType) {
switch (detectorType) {
case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
@@ -151,4 +170,15 @@
return HOTWORD_DETECTOR_EVENTS__DETECTOR_TYPE__NORMAL_DETECTOR;
}
}
+
+ private static int getAudioEgressDetectorType(int detectorType) {
+ switch (detectorType) {
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_SOFTWARE:
+ return AUDIO_EGRESS_SOFTWARE_DETECTOR;
+ case HotwordDetector.DETECTOR_TYPE_TRUSTED_HOTWORD_DSP:
+ return AUDIO_EGRESS_DSP_DETECTOR;
+ default:
+ return AUDIO_EGRESS_NORMAL_DETECTOR;
+ }
+ }
}