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