diff options
author | Jay Thomas Sullivan <jaysullivan@google.com> | 2023-01-10 15:25:34 -0800 |
---|---|---|
committer | Jay Sullivan <jaysullivan@google.com> | 2023-01-14 20:07:16 +0000 |
commit | a638184ac2ddd722e7ea531224624c07140a04a8 (patch) | |
tree | 39adaadc7efda83233a8590b33cb9bc050f474d6 /PermissionController/src/com/android/permissioncontroller/permission/service | |
parent | c0ac44e130282678b9da4dea65c49d8c50ff6907 (diff) | |
download | Permission-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.kt | 79 |
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 |