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