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 66 /** Data class representing the information about an app. */ 67 data class AppInfo( 68 val packageName: String, 69 ) 70 71 /** Data class representing an app's safety label. */ 72 data class SafetyLabel( 73 /** Information about the app. */ 74 val appInfo: AppInfo, 75 /** Earliest time at which the safety label was known to be accurate. */ 76 val receivedAt: Instant, 77 /** Information about data use policies for an app. */ 78 val dataLabel: DataLabel 79 ) { 80 /** Companion object for [SafetyLabel]. */ 81 companion object { 82 /** 83 * Creates a safety label for persistence from the safety label parsed from 84 * PackageManager app metadata. 85 */ 86 fun extractLocationSharingSafetyLabel( 87 packageName: String, 88 receivedAt: Instant, 89 appMetadataSafetyLabel: AppMetadataSafetyLabel 90 ): SafetyLabel = 91 SafetyLabel( 92 AppInfo(packageName), 93 receivedAt, 94 DataLabel.extractLocationSharingDataLabel(appMetadataSafetyLabel.dataLabel) 95 ) 96 } 97 } 98 99 /** Data class representing an app's data use policies. */ 100 data class DataLabel( 101 /** Map of category to [DataCategory] */ 102 val dataShared: Map<String, DataCategory> 103 ) { 104 /** Companion object for [DataCategory]. */ 105 companion object { 106 /** 107 * Creates a data label for persistence from a data label parsed from PackageManager app 108 * metadata. 109 */ 110 fun extractLocationSharingDataLabel( 111 appMetadataDataLabel: AppMetadataDataLabel 112 ): DataLabel = 113 DataLabel( 114 appMetadataDataLabel.dataShared 115 .filter { it.key == DataCategoryConstants.CATEGORY_LOCATION } 116 .mapValues { categoryEntry -> 117 DataCategory.fromAppMetadataDataCategory(categoryEntry.value) 118 } 119 ) 120 } 121 } 122 123 /** Data class representing an app's data use for a particular category of data. */ 124 data class DataCategory( 125 /** Whether any data in this category has been used for Advertising. */ 126 val containsAdvertisingPurpose: Boolean 127 ) { 128 /** Companion object for [DataCategory]. */ 129 companion object { 130 /** 131 * Creates a data category for persistence from a data category parsed from 132 * PackageManager app metadata. 133 */ 134 fun fromAppMetadataDataCategory( 135 appMetadataDataCategory: AppMetadataDataCategory 136 ): DataCategory = 137 DataCategory( 138 appMetadataDataCategory.dataTypes.values.any { 139 it.purposeSet.contains(PURPOSE_ADVERTISING) 140 } 141 ) 142 } 143 } 144 145 /** Data class representing a change of an app's safety label over time. */ 146 data class AppSafetyLabelDiff( 147 val safetyLabelBefore: SafetyLabel, 148 val safetyLabelAfter: SafetyLabel 149 ) { 150 init { 151 require(safetyLabelBefore.appInfo == safetyLabelAfter.appInfo) 152 } 153 } 154 } 155