1 /* 2 * Copyright (C) 2023 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.car.hal.property; 18 19 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_DEFAULT; 20 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_1; 21 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_10; 22 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_2; 23 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_3; 24 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_4; 25 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_5; 26 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_6; 27 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_7; 28 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_8; 29 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_9; 30 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_DOOR; 31 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_ENGINE; 32 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_HVAC; 33 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_INFO; 34 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_LIGHT; 35 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_MIRROR; 36 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_SEAT; 37 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_GET_VENDOR_CATEGORY_WINDOW; 38 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_NOT_ACCESSIBLE; 39 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_1; 40 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_10; 41 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_2; 42 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_3; 43 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_4; 44 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_5; 45 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_6; 46 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_7; 47 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_8; 48 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_9; 49 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_DOOR; 50 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_ENGINE; 51 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_HVAC; 52 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_INFO; 53 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_LIGHT; 54 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_MIRROR; 55 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_SEAT; 56 import static android.hardware.automotive.vehicle.VehicleVendorPermission.PERMISSION_SET_VENDOR_CATEGORY_WINDOW; 57 58 import android.annotation.Nullable; 59 import android.car.Car; 60 import android.car.hardware.property.VehicleVendorPermission; 61 import android.content.Context; 62 import android.content.pm.PackageManager; 63 import android.util.ArraySet; 64 65 import com.android.internal.annotations.VisibleForTesting; 66 67 import java.util.Collections; 68 import java.util.Objects; 69 70 /** 71 * This utility class provides helper method to deal with property permission. 72 */ 73 public class PropertyPermissionInfo { 74 /** 75 * The builder for {@link PropertyPermissions}. 76 */ 77 public static final class PropertyPermissionsBuilder { 78 @Nullable 79 private PermissionCondition mReadPermission; 80 @Nullable 81 private PermissionCondition mWritePermission; 82 83 /** 84 * Sets the read permission. 85 */ setReadPermission(PermissionCondition readPermission)86 public PropertyPermissionsBuilder setReadPermission(PermissionCondition readPermission) { 87 mReadPermission = readPermission; 88 return this; 89 } 90 91 /** 92 * Sets the write permission. 93 */ setWritePermission(PermissionCondition writePermission)94 public PropertyPermissionsBuilder setWritePermission(PermissionCondition writePermission) { 95 mWritePermission = writePermission; 96 return this; 97 } 98 99 /** 100 * Builds the permission. 101 */ build()102 public PropertyPermissions build() { 103 if (mReadPermission == null && mWritePermission == null) { 104 throw new IllegalStateException("Both read and write permissions have not been " 105 + "set"); 106 } 107 return new PropertyPermissions(mReadPermission, mWritePermission); 108 } 109 } 110 111 /** 112 * Class to hold {@code readPermission} and {@code writePermission} in a single object. 113 */ PropertyPermissions( @ullable PermissionCondition readPermission, @Nullable PermissionCondition writePermission)114 /* package */ record PropertyPermissions( 115 @Nullable PermissionCondition readPermission, 116 @Nullable PermissionCondition writePermission) {} 117 118 /** 119 * An interface for representing the read and write permissions required for each property. 120 * <p> 121 * <p>If a property requires only a singular permission for read or write, that permission 122 * should be instantiated in a {@link SinglePermission} class. If the property requires multiple 123 * permissions, the {@link AllOfPermissions} class should be used. If the property requires one 124 * out of any group of permissions, the {@link AnyOfPermissions} class should be used. If a 125 * combination of these is required for read or write, a combination of AllOfPermissions and 126 * AnyOfPermissions should be used as described in their javadocs. 127 */ 128 public interface PermissionCondition { 129 130 /** 131 * Determines whether the condition defined in the class has been met or not, within a given 132 * context. 133 * 134 * @param context Context to check 135 * @return whether required permission are granted. 136 */ isMet(Context context)137 boolean isMet(Context context); 138 } 139 140 /** 141 * Implementation to store {@code allOf()} permission sets. 142 * <p> 143 * <p>This implementation of {@link PermissionCondition} stores the permissions that a property 144 * would require all of in order to be granted. AllOfPermissions stores the permissions as a 145 * {@code ArraySet<PermissionCondition>}, so singular permissions in AllOfPermissions will be 146 * stored as {@link SinglePermission} objects in the list, and a set of anyOf permissions will 147 * be stored as {@link AnyOfPermissions} objects. 148 */ 149 public static final class AllOfPermissions implements PermissionCondition { 150 private final ArraySet<PermissionCondition> mPermissionsList; 151 AllOfPermissions(PermissionCondition... permissions)152 public AllOfPermissions(PermissionCondition... permissions) { 153 if (permissions.length <= 1) { 154 throw new IllegalArgumentException("Input parameter should contain at least 2 " 155 + "PermissionCondition objects"); 156 } 157 mPermissionsList = new ArraySet<>(); 158 Collections.addAll(mPermissionsList, permissions); 159 } 160 161 /** 162 * Checks whether every {@link PermissionCondition} in this object has been granted by the 163 * given context or not. 164 * 165 * @param context Context to check 166 * @return whether all permissions in the AllOfPermissions object are met. 167 */ isMet(Context context)168 public boolean isMet(Context context) { 169 for (int i = 0; i < mPermissionsList.size(); i++) { 170 if (!mPermissionsList.valueAt(i).isMet(context)) { 171 return false; 172 } 173 } 174 return true; 175 } 176 177 @Override toString()178 public String toString() { 179 StringBuilder stringBuffer = new StringBuilder().append('('); 180 for (int i = 0; i < mPermissionsList.size() - 1; i++) { 181 stringBuffer.append(mPermissionsList.valueAt(i).toString()); 182 stringBuffer.append(" && "); 183 } 184 stringBuffer.append(mPermissionsList.valueAt(mPermissionsList.size() - 1)).append(')'); 185 return stringBuffer.toString(); 186 } 187 188 @Override equals(Object object)189 public boolean equals(Object object) { 190 if (this == object) { 191 return true; 192 } 193 // instanceof will return false if object is null. 194 if (!(object instanceof AllOfPermissions)) { 195 return false; 196 } 197 return mPermissionsList.equals(((AllOfPermissions) object).mPermissionsList); 198 } 199 200 @Override hashCode()201 public int hashCode() { 202 return Objects.hashCode(mPermissionsList) + "all".hashCode(); 203 } 204 } 205 206 /** 207 * Implementation to store {@code anyOf()} permission sets. 208 * <p> 209 * <p>This implementation of {@link PermissionCondition} stores the permissions that a property 210 * would require any of in order to be granted. AnyOfPermissions stores the permissions as a 211 * {@code ArraySet<PermissionCondition>}, so singular permissions in AnyOfPermissions will be 212 * stored as {@link SinglePermission} objects in the list, and a set of allOf permissions will 213 * be stored as {@link AllOfPermissions} objects. 214 */ 215 public static final class AnyOfPermissions implements PermissionCondition { 216 private final ArraySet<PermissionCondition> mPermissionsList; 217 AnyOfPermissions(PermissionCondition... permissions)218 public AnyOfPermissions(PermissionCondition... permissions) { 219 if (permissions.length <= 1) { 220 throw new IllegalArgumentException("Input parameter should contain at least 2 " 221 + "PermissionCondition objects"); 222 } 223 mPermissionsList = new ArraySet<>(); 224 Collections.addAll(mPermissionsList, permissions); 225 } 226 227 /** 228 * Checks whether any {@link PermissionCondition} in this object has been granted by the 229 * given context or not. 230 * 231 * @param context Context to check 232 * @return whether any permission in the AnyOfPermissions object has been met. 233 */ isMet(Context context)234 public boolean isMet(Context context) { 235 for (int i = 0; i < mPermissionsList.size(); i++) { 236 if (mPermissionsList.valueAt(i).isMet(context)) { 237 return true; 238 } 239 } 240 return false; 241 } 242 243 @Override toString()244 public String toString() { 245 StringBuilder stringBuffer = new StringBuilder().append('('); 246 for (int i = 0; i < mPermissionsList.size() - 1; i++) { 247 stringBuffer.append(mPermissionsList.valueAt(i).toString()); 248 stringBuffer.append(" || "); 249 } 250 stringBuffer.append(mPermissionsList.valueAt(mPermissionsList.size() - 1)).append(')'); 251 return stringBuffer.toString(); 252 } 253 254 @Override equals(Object object)255 public boolean equals(Object object) { 256 if (this == object) { 257 return true; 258 } 259 // instanceof will return false if object is null. 260 if (!(object instanceof AnyOfPermissions)) { 261 return false; 262 } 263 return mPermissionsList.equals(((AnyOfPermissions) object).mPermissionsList); 264 } 265 266 @Override hashCode()267 public int hashCode() { 268 return Objects.hashCode(mPermissionsList) + "any".hashCode(); 269 } 270 271 /** 272 * Checks whether current {@link PermissionCondition} instance will be met if given {@link 273 * SinglePermission} instance is known to be granted. 274 * 275 * <p>To be used for testing only 276 * 277 * @param grantedPermission {@link SinglePermission} that is known to be granted. 278 * @return whether current AnyOfPermissions object is met. 279 */ 280 @VisibleForTesting isMetIfGranted(SinglePermission grantedPermission)281 public boolean isMetIfGranted(SinglePermission grantedPermission) { 282 for (int i = 0; i < mPermissionsList.size(); i++) { 283 if (mPermissionsList.valueAt(i).equals(grantedPermission)) { 284 return true; 285 } 286 } 287 return false; 288 } 289 } 290 291 /** 292 * Implementation to store a singular permission string. 293 * <p> 294 * <p>This implementation of {@link PermissionCondition} holds a singular permission. This class 295 * is used to hold individual permissions on their own in the property-permissions map or within 296 * some other implementation of PermissionCondition. 297 */ 298 public static final class SinglePermission implements PermissionCondition { 299 private final String mPermission; 300 SinglePermission(String permission)301 public SinglePermission(String permission) { 302 mPermission = permission; 303 } 304 305 /** 306 * Checks if the permission is granted in a given context. 307 * 308 * @param context Context to check 309 * @return whether permission has been granted. 310 */ isMet(Context context)311 public boolean isMet(Context context) { 312 return context.checkCallingOrSelfPermission(mPermission) 313 == PackageManager.PERMISSION_GRANTED; 314 } 315 316 @Override toString()317 public String toString() { 318 return mPermission; 319 } 320 321 @Override equals(Object object)322 public boolean equals(Object object) { 323 if (this == object) { 324 return true; 325 } 326 // instanceof will return false if object is null. 327 if (!(object instanceof SinglePermission)) { 328 return false; 329 } 330 return mPermission.equals(((SinglePermission) object).mPermission); 331 } 332 333 @Override hashCode()334 public int hashCode() { 335 return mPermission.hashCode() + "single".hashCode(); 336 } 337 } 338 339 /** 340 * Maps VehicleVendorPermission enums in VHAL to android permissions. 341 * 342 * @return permission string, return null if vendor property is not available. 343 */ 344 @Nullable toPermissionString(int permissionEnum, int propId)345 public static String toPermissionString(int permissionEnum, int propId) { 346 switch (permissionEnum) { 347 case PERMISSION_DEFAULT: 348 return Car.PERMISSION_VENDOR_EXTENSION; 349 case PERMISSION_SET_VENDOR_CATEGORY_WINDOW: 350 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_WINDOW; 351 case PERMISSION_GET_VENDOR_CATEGORY_WINDOW: 352 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_WINDOW; 353 case PERMISSION_SET_VENDOR_CATEGORY_DOOR: 354 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_DOOR; 355 case PERMISSION_GET_VENDOR_CATEGORY_DOOR: 356 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_DOOR; 357 case PERMISSION_SET_VENDOR_CATEGORY_SEAT: 358 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_SEAT; 359 case PERMISSION_GET_VENDOR_CATEGORY_SEAT: 360 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_SEAT; 361 case PERMISSION_SET_VENDOR_CATEGORY_MIRROR: 362 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_MIRROR; 363 case PERMISSION_GET_VENDOR_CATEGORY_MIRROR: 364 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_MIRROR; 365 case PERMISSION_SET_VENDOR_CATEGORY_INFO: 366 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_INFO; 367 case PERMISSION_GET_VENDOR_CATEGORY_INFO: 368 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_INFO; 369 case PERMISSION_SET_VENDOR_CATEGORY_ENGINE: 370 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_ENGINE; 371 case PERMISSION_GET_VENDOR_CATEGORY_ENGINE: 372 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_ENGINE; 373 case PERMISSION_SET_VENDOR_CATEGORY_HVAC: 374 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_HVAC; 375 case PERMISSION_GET_VENDOR_CATEGORY_HVAC: 376 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_HVAC; 377 case PERMISSION_SET_VENDOR_CATEGORY_LIGHT: 378 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_LIGHT; 379 case PERMISSION_GET_VENDOR_CATEGORY_LIGHT: 380 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_LIGHT; 381 case PERMISSION_SET_VENDOR_CATEGORY_1: 382 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_1; 383 case PERMISSION_GET_VENDOR_CATEGORY_1: 384 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_1; 385 case PERMISSION_SET_VENDOR_CATEGORY_2: 386 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_2; 387 case PERMISSION_GET_VENDOR_CATEGORY_2: 388 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_2; 389 case PERMISSION_SET_VENDOR_CATEGORY_3: 390 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_3; 391 case PERMISSION_GET_VENDOR_CATEGORY_3: 392 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_3; 393 case PERMISSION_SET_VENDOR_CATEGORY_4: 394 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_4; 395 case PERMISSION_GET_VENDOR_CATEGORY_4: 396 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_4; 397 case PERMISSION_SET_VENDOR_CATEGORY_5: 398 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_5; 399 case PERMISSION_GET_VENDOR_CATEGORY_5: 400 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_5; 401 case PERMISSION_SET_VENDOR_CATEGORY_6: 402 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_6; 403 case PERMISSION_GET_VENDOR_CATEGORY_6: 404 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_6; 405 case PERMISSION_SET_VENDOR_CATEGORY_7: 406 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_7; 407 case PERMISSION_GET_VENDOR_CATEGORY_7: 408 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_7; 409 case PERMISSION_SET_VENDOR_CATEGORY_8: 410 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_8; 411 case PERMISSION_GET_VENDOR_CATEGORY_8: 412 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_8; 413 case PERMISSION_SET_VENDOR_CATEGORY_9: 414 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_9; 415 case PERMISSION_GET_VENDOR_CATEGORY_9: 416 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_9; 417 case PERMISSION_SET_VENDOR_CATEGORY_10: 418 return VehicleVendorPermission.PERMISSION_SET_CAR_VENDOR_CATEGORY_10; 419 case PERMISSION_GET_VENDOR_CATEGORY_10: 420 return VehicleVendorPermission.PERMISSION_GET_CAR_VENDOR_CATEGORY_10; 421 case PERMISSION_NOT_ACCESSIBLE: 422 return null; 423 default: 424 throw new IllegalArgumentException("permission Id: " + permissionEnum 425 + " for property:" + propId + " is invalid vendor permission Id"); 426 } 427 } 428 PropertyPermissionInfo()429 private PropertyPermissionInfo() { 430 throw new IllegalStateException("Only allowed to be used as static"); 431 } 432 } 433