1 /* 2 * Copyright (C) 2024 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.server.healthconnect.permission; 18 19 import static android.health.connect.HealthPermissions.WRITE_MEDICAL_DATA; 20 import static android.health.connect.internal.datatypes.utils.MedicalResourceTypePermissionMapper.getMedicalReadPermission; 21 import static android.permission.PermissionManager.PERMISSION_GRANTED; 22 23 import android.content.AttributionSource; 24 import android.health.connect.HealthPermissions; 25 import android.health.connect.datatypes.MedicalResource; 26 import android.permission.PermissionManager; 27 import android.util.ArraySet; 28 29 import java.util.Set; 30 31 /** 32 * Helper class to force caller of medical data apis to hold api required permissions. 33 * 34 * @hide 35 */ 36 public class MedicalDataPermissionEnforcer { 37 private final PermissionManager mPermissionManager; 38 MedicalDataPermissionEnforcer(PermissionManager permissionManager)39 public MedicalDataPermissionEnforcer(PermissionManager permissionManager) { 40 mPermissionManager = permissionManager; 41 } 42 43 /** 44 * Enforces that caller has write permission for medical data. 45 * 46 * @throws SecurityException if the app does not have write permission. 47 */ enforceWriteMedicalDataPermission(AttributionSource attributionSource)48 public void enforceWriteMedicalDataPermission(AttributionSource attributionSource) { 49 if (!isPermissionGranted(WRITE_MEDICAL_DATA, attributionSource)) { 50 throw new SecurityException( 51 "Caller doesn't have " + WRITE_MEDICAL_DATA + " to write MedicalResource"); 52 } 53 } 54 55 /** 56 * Enforces that caller has either read or write permissions for given medicalResourceType. 57 * Returns {@code true} if the caller is allowed to read only records written by itself, false 58 * if the caller is allowed to read records written by any apps including itself. 59 * 60 * @throws SecurityException if the app has neither read nor write permissions for any of the 61 * specified medical resources. 62 */ enforceMedicalReadAccessAndGetEnforceSelfRead( @edicalResource.MedicalResourceType int medicalResourceType, AttributionSource attributionSource)63 public boolean enforceMedicalReadAccessAndGetEnforceSelfRead( 64 @MedicalResource.MedicalResourceType int medicalResourceType, 65 AttributionSource attributionSource) { 66 String readPermissionName = getMedicalReadPermission(medicalResourceType); 67 68 if (isPermissionGranted(readPermissionName, attributionSource)) { 69 return false; 70 } 71 72 if (isPermissionGranted(WRITE_MEDICAL_DATA, attributionSource)) { 73 // Apps are always allowed to read self data if they have insert permission. 74 return true; 75 } 76 throw new SecurityException( 77 "Caller doesn't have " + readPermissionName + " to read MedicalResource"); 78 } 79 80 /** 81 * Returns a list of read or write medical permissions the caller has been granted permission to 82 * access. Uses checkPermissionForPreflight as this method is not used for delivering data but 83 * checking permission state. 84 */ getGrantedMedicalPermissionsForPreflight( AttributionSource attributionSource)85 public Set<String> getGrantedMedicalPermissionsForPreflight( 86 AttributionSource attributionSource) { 87 Set<String> grantedPermissions = new ArraySet<>(); 88 89 for (String permission : HealthPermissions.getAllMedicalPermissions()) { 90 if (mPermissionManager.checkPermissionForPreflight(permission, attributionSource) 91 == PERMISSION_GRANTED) { 92 grantedPermissions.add(permission); 93 } 94 } 95 return grantedPermissions; 96 } 97 isPermissionGranted( String permissionName, AttributionSource attributionSource)98 private boolean isPermissionGranted( 99 String permissionName, AttributionSource attributionSource) { 100 return mPermissionManager.checkPermissionForDataDelivery( 101 permissionName, attributionSource, null) 102 == PERMISSION_GRANTED; 103 } 104 } 105