"Fix" NPE in PhoneStatusBarPolicy
Callback returns a copy of the list
Makes PrivacyItemController dumpable
Test: atest
Test: adb shell dumpsys activity service com.android.systemui/.SystemUIService Dependency
Fixes: 124234367
Change-Id: I1400ee8294f34b129723bb0f0ce7745dafaf5545
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
index f7ca51d..a6e48f8 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItem.kt
@@ -62,4 +62,6 @@
context.packageManager.getApplicationLabel(it) as String
} ?: packageName
}
+
+ override fun toString() = "PrivacyApplication(packageName=$packageName, uid=$uid)"
}
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
index 0f33937..625eacd 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/PrivacyItemController.kt
@@ -31,6 +31,9 @@
import com.android.systemui.R
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
+import com.android.systemui.Dumpable
+import java.io.FileDescriptor
+import java.io.PrintWriter
import java.lang.ref.WeakReference
import javax.inject.Inject
import javax.inject.Named
@@ -42,7 +45,7 @@
private val appOpsController: AppOpsController,
@Named(MAIN_HANDLER_NAME) private val uiHandler: Handler,
@Named(BG_HANDLER_NAME) private val bgHandler: Handler
-) {
+) : Dumpable {
companion object {
val OPS = intArrayOf(AppOpsManager.OP_CAMERA,
@@ -56,7 +59,10 @@
const val SYSTEM_UID = 1000
}
- private var privacyList = emptyList<PrivacyItem>()
+ @VisibleForTesting
+ internal var privacyList = emptyList<PrivacyItem>()
+ get() = field.toList() // Provides a shallow copy of the list
+
private val userManager = context.getSystemService(UserManager::class.java)
private var currentUserIds = emptyList<Int>()
private var listening = false
@@ -189,4 +195,22 @@
callback?.privacyChanged(list)
}
}
+
+ override fun dump(fd: FileDescriptor?, pw: PrintWriter?, args: Array<out String>?) {
+ pw?.println("PrivacyItemController state:")
+ pw?.println(" Listening: $listening")
+ pw?.println(" Current user ids: $currentUserIds")
+ pw?.println(" Privacy Items:")
+ privacyList.forEach {
+ pw?.print(" ")
+ pw?.println(it.toString())
+ }
+ pw?.println(" Callbacks:")
+ callbacks.forEach {
+ it.get()?.let {
+ pw?.print(" ")
+ pw?.println(it.toString())
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 2799191..e0c5e59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -92,6 +92,8 @@
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.NotificationChannels;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.util.List;
import java.util.Locale;
@@ -793,6 +795,15 @@
boolean showMicrophone = false;
boolean showLocation = false;
for (PrivacyItem item : items) {
+ if (item == null /* b/124234367 */) {
+ if (DEBUG) {
+ Log.e(TAG, "updatePrivacyItems - null item found");
+ StringWriter out = new StringWriter();
+ mPrivacyItemController.dump(null, new PrintWriter(out), null);
+ Log.e(TAG, out.toString());
+ }
+ continue;
+ }
switch (item.getPrivacyType()) {
case TYPE_CAMERA:
showCamera = true;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
index 5d3f6ca..bb384dd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/privacy/PrivacyItemControllerTest.kt
@@ -35,7 +35,12 @@
import com.android.systemui.SysuiTestCase
import com.android.systemui.appops.AppOpItem
import com.android.systemui.appops.AppOpsController
+import org.hamcrest.Matchers.hasItem
+import org.hamcrest.Matchers.not
+import org.hamcrest.Matchers.nullValue
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertThat
+import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -240,4 +245,26 @@
verify(callback, never()).privacyChanged(anyList())
verify(otherCallback).privacyChanged(anyList())
}
+
+ @Test
+ fun testListShouldNotHaveNull() {
+ doReturn(listOf(AppOpItem(AppOpsManager.OP_ACTIVATE_VPN, TEST_UID, "", 0),
+ AppOpItem(AppOpsManager.OP_COARSE_LOCATION, TEST_UID, "", 0)))
+ .`when`(appOpsController).getActiveAppOpsForUser(anyInt())
+ privacyItemController.addCallback(callback)
+ testableLooper.processAllMessages()
+
+ verify(callback).privacyChanged(capture(argCaptor))
+ assertEquals(1, argCaptor.value.size)
+ assertThat(argCaptor.value, not(hasItem(nullValue())))
+ }
+
+ @Test
+ fun testListShouldBeCopy() {
+ val list = listOf(PrivacyItem(PrivacyType.TYPE_CAMERA,
+ PrivacyApplication("", TEST_UID, mContext)))
+ privacyItemController.privacyList = list
+ assertEquals(list, privacyItemController.privacyList)
+ assertTrue(list !== privacyItemController.privacyList)
+ }
}
\ No newline at end of file