summaryrefslogtreecommitdiff
path: root/PermissionController/src/com/android/permissioncontroller/permission/service
diff options
context:
space:
mode:
authorJay Thomas Sullivan <jaysullivan@google.com>2023-01-10 15:25:34 -0800
committerJay Sullivan <jaysullivan@google.com>2023-01-14 20:07:16 +0000
commita638184ac2ddd722e7ea531224624c07140a04a8 (patch)
tree39adaadc7efda83233a8590b33cb9bc050f474d6 /PermissionController/src/com/android/permissioncontroller/permission/service
parentc0ac44e130282678b9da4dea65c49d8c50ff6907 (diff)
downloadPermission-a638184ac2ddd722e7ea531224624c07140a04a8.tar.gz
[Safety Labels] Initialize safety labels
Each time the safety labels job runs, load initial safety labels for any (applicable) packages which have not already been loaded. This also does a few semi-related fixes: - Invoke an intent action upon clicking the notification - Handle onStopJob properly - Remove onStartMainJob_notificationShown test until we find away to mock LiveData repository Test: atest PermissionControllerMockingTests SafetyLabelChangesJobServiceTest Bug: 261663926 Change-Id: I6fd5256473546f7126d11629f5bab2205800e718
Diffstat (limited to 'PermissionController/src/com/android/permissioncontroller/permission/service')
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt79
1 files changed, 76 insertions, 3 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
index 738c152be..946e5f121 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/v34/SafetyLabelChangesJobService.kt
@@ -16,8 +16,10 @@
package com.android.permissioncontroller.permission.service.v34
+import android.Manifest
import android.app.NotificationChannel
import android.app.NotificationManager
+import android.app.PendingIntent
import android.app.job.JobInfo
import android.app.job.JobParameters
import android.app.job.JobScheduler
@@ -28,20 +30,32 @@ import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_BOOT_COMPLETED
import android.os.Build
+import android.os.UserHandle
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
+import com.android.permission.safetylabel.SafetyLabel
import com.android.permissioncontroller.Constants.PERIODIC_SAFETY_LABEL_CHANGES_JOB_ID
import com.android.permissioncontroller.Constants.PERMISSION_REMINDER_CHANNEL_ID
import com.android.permissioncontroller.Constants.SAFETY_LABEL_CHANGES_JOB_ID
import com.android.permissioncontroller.Constants.SAFETY_LABEL_CHANGES_NOTIFICATION_ID
import com.android.permissioncontroller.PermissionControllerApplication
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.data.LightInstallSourceInfoLiveData
+import com.android.permissioncontroller.permission.data.SinglePermGroupPackagesUiInfoLiveData
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.Utils.getSystemServiceSafe
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistory
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence
+import com.android.permissioncontroller.safetylabel.AppsSafetyLabelHistoryPersistence.getPackagesWithSafetyLabels
+import java.time.Instant
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
/**
* Runs a monthly job that performs Safety Labels-related tasks, e.g., data policy changes
@@ -49,6 +63,8 @@ import kotlinx.coroutines.launch
*/
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
class SafetyLabelChangesJobService : JobService() {
+ private var mainJobTask: Job? = null
+
class Receiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (!KotlinUtils.isSafetyLabelChangeNotificationsEnabled()) {
@@ -82,7 +98,7 @@ class SafetyLabelChangesJobService : JobService() {
}
private fun dispatchMainJobTask(params: JobParameters) {
- GlobalScope.launch(Dispatchers.Default) {
+ mainJobTask = GlobalScope.launch(Dispatchers.Default) {
try {
Log.i(LOG_TAG, "Job started")
runMainJob()
@@ -96,10 +112,53 @@ class SafetyLabelChangesJobService : JobService() {
}
}
- private fun runMainJob() {
+ private suspend fun runMainJob() {
+ initializeSafetyLabels()
postSafetyLabelChangedNotification()
}
+ private suspend fun initializeSafetyLabels() {
+ val context = PermissionControllerApplication.get() as Context
+ val historyFile = AppsSafetyLabelHistoryPersistence.getSafetyLabelHistoryFile(context)
+
+ val packageNamesWithoutPersistedSafetyLabels: Set<String> =
+ getAllNonPreinstalledPackageNamesRequestingLocation() -
+ getPackagesWithSafetyLabels(historyFile)
+
+ for (packageName in packageNamesWithoutPersistedSafetyLabels) {
+ yield() // cancellation point
+
+ val appMetadataBundle = context.packageManager.getAppMetadata(packageName)
+ val safetyLabel: SafetyLabel =
+ SafetyLabel.getSafetyLabelFromMetadata(appMetadataBundle) ?: continue
+ // TODO(b/264884404): Use install time or last update time for an app for the time a
+ // safety label is received instead of current time.
+ val safetyLabelForPersistence =
+ AppsSafetyLabelHistory.SafetyLabel.fromAppMetadataSafetyLabel(
+ packageName, receivedAt = Instant.now(), safetyLabel)
+ // TODO(b/265380622): Add a method to record safety labels in bulk rather than calling
+ // recordSafetyLabel once per package
+ AppsSafetyLabelHistoryPersistence
+ .recordSafetyLabel(safetyLabelForPersistence, historyFile)
+ }
+ }
+
+ private suspend fun getAllNonPreinstalledPackageNamesRequestingLocation(): Set<String> =
+ getAllPackagesRequestingLocation()
+ .filter { !isPreinstalledPackage(it) }
+ .map { (packageName, _) -> packageName }
+ .toSet()
+
+ private suspend fun getAllPackagesRequestingLocation(): Set<Pair<String, UserHandle>> =
+ SinglePermGroupPackagesUiInfoLiveData[Manifest.permission_group.LOCATION]
+ .getInitializedValue()
+ .keys
+
+ private suspend fun isPreinstalledPackage(pkg: Pair<String, UserHandle>): Boolean =
+ LightInstallSourceInfoLiveData[pkg]
+ .getInitializedValue()
+ .installingPackageName == null
+
private fun postSafetyLabelChangedNotification() {
if (hasDataSharingChanged()) {
Log.i(LOG_TAG, "Showing notification: data sharing has changed")
@@ -109,7 +168,13 @@ class SafetyLabelChangesJobService : JobService() {
}
}
- override fun onStopJob(params: JobParameters?): Boolean = true
+ override fun onStopJob(params: JobParameters?): Boolean {
+ runBlocking {
+ mainJobTask?.cancelAndJoin()
+ mainJobTask = null
+ }
+ return true
+ }
private fun hasDataSharingChanged(): Boolean {
// TODO(b/261663886): Check whether data sharing has changed
@@ -132,11 +197,19 @@ class SafetyLabelChangesJobService : JobService() {
.setLocalOnly(true)
.setAutoCancel(true)
.setSilent(true)
+ .setContentIntent(createIntentToOpenAppDataSharingUpdates(context))
.build()
notificationManager.notify(SAFETY_LABEL_CHANGES_NOTIFICATION_ID, notification)
}
+ private fun createIntentToOpenAppDataSharingUpdates(context: Context): PendingIntent? {
+ return PendingIntent.getActivity(
+ context, 0, Intent(Intent.ACTION_REVIEW_APP_DATA_SHARING_UPDATES),
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
private fun createNotificationChannel(
context: Context,
notificationManager: NotificationManager