1 /* <lambda>null2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.permissioncontroller.safetylabel 18 19 import com.android.permission.safetylabel.DataCategory as AppMetadataDataCategory 20 import com.android.permission.safetylabel.DataCategoryConstants 21 import com.android.permission.safetylabel.DataLabel as AppMetadataDataLabel 22 import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING 23 import com.android.permission.safetylabel.SafetyLabel as AppMetadataSafetyLabel 24 import java.time.Instant 25 26 /** Data class representing safety label history of installed apps. */ 27 data class AppsSafetyLabelHistory(val appSafetyLabelHistories: List<AppSafetyLabelHistory>) { 28 29 /** Data class representing the safety label history of an app. */ 30 data class AppSafetyLabelHistory( 31 /** Information about the app. */ 32 val appInfo: AppInfo, 33 /** 34 * A list of [SafetyLabel]s that this app has had in the past, ordered by 35 * [SafetyLabel.receivedAt]. 36 * 37 * The last [SafetyLabel] in this list can be considered the last known [SafetyLabel] of the 38 * app. 39 */ 40 val safetyLabelHistory: List<SafetyLabel> 41 ) { 42 init { 43 require(safetyLabelHistory.sortedBy { it.receivedAt } == safetyLabelHistory) 44 require(safetyLabelHistory.all { it.appInfo == appInfo }) 45 } 46 47 /** 48 * Returns an [AppSafetyLabelHistory] with the original history as well the provided safety 49 * label, ensuring that the maximum number of safety labels stored for this app does not 50 * exceed [maxToPersist]. 51 * 52 * If the storage already has [maxToPersist] labels or more, the oldest will be discarded to 53 * make space for the newly added safety label. 54 */ 55 fun withSafetyLabel(safetyLabel: SafetyLabel, maxToPersist: Int): AppSafetyLabelHistory = 56 AppSafetyLabelHistory( 57 appInfo, 58 safetyLabelHistory 59 .toMutableList() 60 .apply { add(safetyLabel) } 61 .sortedBy { it.receivedAt } 62 .takeLast(maxToPersist)) 63 } 64 65 /** Data class representing the information about an app. */ 66 data class AppInfo( 67 val packageName: String, 68 ) 69 70 /** Data class representing an app's safety label. */ 71 data class SafetyLabel( 72 /** Information about the app. */ 73 val appInfo: AppInfo, 74 /** Earliest time at which the safety label was known to be accurate. */ 75 val receivedAt: Instant, 76 /** Information about data use policies for an app. */ 77 val dataLabel: DataLabel 78 ) { 79 /** Companion object for [SafetyLabel]. */ 80 companion object { 81 /** 82 * Creates a safety label for persistence from the safety label parsed from 83 * PackageManager app metadata. 84 */ 85 fun extractLocationSharingSafetyLabel( 86 packageName: String, 87 receivedAt: Instant, 88 appMetadataSafetyLabel: AppMetadataSafetyLabel 89 ): SafetyLabel = 90 SafetyLabel( 91 AppInfo(packageName), 92 receivedAt, 93 DataLabel.extractLocationSharingDataLabel(appMetadataSafetyLabel.dataLabel)) 94 } 95 } 96 97 /** Data class representing an app's data use policies. */ 98 data class DataLabel( 99 /** Map of category to [DataCategory] */ 100 val dataShared: Map<String, DataCategory> 101 ) { 102 /** Companion object for [DataCategory]. */ 103 companion object { 104 /** 105 * Creates a data label for persistence from a data label parsed from PackageManager app 106 * metadata. 107 */ 108 fun extractLocationSharingDataLabel( 109 appMetadataDataLabel: AppMetadataDataLabel 110 ): DataLabel = 111 DataLabel( 112 appMetadataDataLabel.dataShared 113 .filter { it.key == DataCategoryConstants.CATEGORY_LOCATION } 114 .mapValues { categoryEntry -> 115 DataCategory.fromAppMetadataDataCategory(categoryEntry.value) 116 }) 117 } 118 } 119 120 /** Data class representing an app's data use for a particular category of data. */ 121 data class DataCategory( 122 /** Whether any data in this category has been used for Advertising. */ 123 val containsAdvertisingPurpose: Boolean 124 ) { 125 /** Companion object for [DataCategory]. */ 126 companion object { 127 /** 128 * Creates a data category for persistence from a data category parsed from 129 * PackageManager app metadata. 130 */ 131 fun fromAppMetadataDataCategory( 132 appMetadataDataCategory: AppMetadataDataCategory 133 ): DataCategory = 134 DataCategory( 135 appMetadataDataCategory.dataTypes.values.any { 136 it.purposeSet.contains(PURPOSE_ADVERTISING) 137 }) 138 } 139 } 140 141 /** Data class representing a change of an app's safety label over time. */ 142 data class AppSafetyLabelDiff( 143 val safetyLabelBefore: SafetyLabel, 144 val safetyLabelAfter: SafetyLabel 145 ) { 146 init { 147 require(safetyLabelBefore.appInfo == safetyLabelAfter.appInfo) 148 } 149 } 150 } 151