1 /*
2  * Copyright (C) 2022 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.rkpdapp.interfaces;
18 
19 import android.annotation.TestApi;
20 import android.hardware.security.keymint.IRemotelyProvisionedComponent;
21 import android.os.ServiceManager;
22 import android.util.Log;
23 
24 import java.util.Arrays;
25 import java.util.Map;
26 import java.util.Objects;
27 
28 /**
29  * Provides convenience methods for interfacing with ServiceManager class and its static functions.
30  */
31 public class ServiceManagerInterface {
32     private static final String TAG = "RkpdSvcManagerInterface";
33     private static SystemInterface[] sInstances;
34     private static Map<String, IRemotelyProvisionedComponent> sBinders;
35 
ServiceManagerInterface()36     private ServiceManagerInterface() {
37     }
38 
tryCreateSystemInterface(IRemotelyProvisionedComponent binder, String serviceName)39     private static SystemInterface tryCreateSystemInterface(IRemotelyProvisionedComponent binder,
40             String serviceName) {
41         try {
42             return new SystemInterface(binder, serviceName);
43         } catch (UnsupportedOperationException e) {
44             Log.i(TAG, serviceName + " is unsupported.");
45             return null;
46         }
47     }
48 
getBinder(String serviceName)49     private static IRemotelyProvisionedComponent getBinder(String serviceName) {
50         IRemotelyProvisionedComponent binder = IRemotelyProvisionedComponent.Stub.asInterface(
51                 ServiceManager.waitForDeclaredService(serviceName));
52         if (binder == null) {
53             throw new IllegalArgumentException("Cannot find any implementation for " + serviceName);
54         }
55         return binder;
56     }
57 
58     /**
59      * Gets all the instances on this device for IRemotelyProvisionedComponent as an array. The
60      * returned values each contain a binder for interacting with the instance.
61      *
62      * For testing purposes, the instances may be overridden by either setInstances or setBinders.
63      */
getAllInstances()64     public static SystemInterface[] getAllInstances() {
65         if (sBinders != null) {
66             return sBinders.entrySet().stream()
67                     .map(x -> tryCreateSystemInterface(x.getValue(), x.getKey()))
68                     .filter(Objects::nonNull)
69                     .toArray(SystemInterface[]::new);
70         }
71         if (sInstances != null) {
72             return sInstances;
73         }
74 
75         String irpcInterface = IRemotelyProvisionedComponent.DESCRIPTOR;
76         return Arrays.stream(ServiceManager.getDeclaredInstances(irpcInterface))
77                 .map(x -> {
78                     String serviceName = irpcInterface + "/" + x;
79                     return tryCreateSystemInterface(getBinder(serviceName), serviceName);
80                 })
81                 .filter(Objects::nonNull)
82                 .toArray(SystemInterface[]::new);
83     }
84 
85     /**
86      * Get a specific system interface instance for a given IRemotelyProvisionedComponent.
87      * If the given serviceName does not map to a known IRemotelyProvisionedComponent, this
88      * method throws IllegalArgumentException.
89      * If the given serviceName is not supported, this method throws UnsupportedOperationException.
90      *
91      * For testing purposes, the instances may be overridden by either setInstances or setBinders.
92      */
getInstance(String serviceName)93     public static SystemInterface getInstance(String serviceName) {
94         if (sBinders != null) {
95             if (sBinders.containsKey(serviceName)) {
96                 return new SystemInterface(sBinders.get(serviceName), serviceName);
97             }
98             throw new IllegalArgumentException("Cannot find any binder for " + serviceName);
99         }
100         if (sInstances != null) {
101             for (SystemInterface i : sInstances) {
102                 if (i.getServiceName().equals(serviceName)) {
103                     return i;
104                 }
105             }
106             throw new IllegalArgumentException("Cannot find any implementation for " + serviceName);
107         }
108 
109         return new SystemInterface(getBinder(serviceName), serviceName);
110     }
111 
112     @TestApi
setInstances(SystemInterface[] instances)113     public static void setInstances(SystemInterface[] instances) {
114         sInstances = instances;
115     }
116 
117     @TestApi
setBinders(Map<String, IRemotelyProvisionedComponent> binders)118     public static void setBinders(Map<String, IRemotelyProvisionedComponent> binders) {
119         sBinders = binders;
120     }
121 }
122