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