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.server.uwb.data;
18 
19 import static com.android.server.uwb.UwbConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION;
20 import static com.android.server.uwb.UwbConfigStore.STORE_FILE_USER_GENERAL;
21 
22 import android.util.Log;
23 
24 import androidx.annotation.Nullable;
25 
26 import com.android.proto.uwb.UwbConfigProto;
27 import com.android.server.uwb.UwbConfigStore;
28 import com.android.server.uwb.util.ObjectIdentifier;
29 
30 import com.google.protobuf.ByteString;
31 
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.UUID;
37 
38 public class ServiceProfileData implements UwbConfigStore.StoreData {
39     private static final String LOG_TAG = "ServiceProfileData";
40 
ServiceProfileData(DataSource dataSource)41     public ServiceProfileData(DataSource dataSource) {
42         this.mDataSource = dataSource;
43     }
44 
45     public static class ServiceProfileInfo {
46         public static final int ADF_STATUS_NOT_PROVISIONED = 0;
47         public static final int ADF_STATUS_CREATED = 1;
48         public static final int ADF_STATUS_PROVISIONED = 2;
49         /**
50          * Unique 128-bit service instance ID
51          */
52         public final UUID serviceInstanceID;
53         /**
54          * App uid
55          */
56         public final int uid;
57         /**
58          * App package name
59          */
60         public final String packageName;
61         /**
62          * Service ID, like PACS or custom service
63          */
64         public final int serviceID;
65         /**
66          * Applet ID for dynamic STS
67          */
68         private int mServiceAppletId;
69 
70         private int mAdfStatus = ADF_STATUS_NOT_PROVISIONED;
71         /**
72          * ADF OID
73          */
74         private Optional<ObjectIdentifier> mServiceAdfOid = Optional.empty();
75 
76         /**
77          * secure blob for ADF.
78          */
79         private Optional<byte[]> mSecureBlob = Optional.empty();
80 
81         /**
82          *
83          * serviceAppletID and serviceAdfOid will be set after provisioning.
84          */
ServiceProfileInfo(UUID serviceInstanceID, int uid, String packageName, int serviceID)85         public ServiceProfileInfo(UUID serviceInstanceID, int uid,
86                 String packageName, int serviceID) {
87             this.serviceInstanceID = serviceInstanceID;
88             this.uid = uid;
89             this.packageName = packageName;
90             this.serviceID = serviceID;
91         }
92 
setServiceAppletId(int serviceAppletId)93         public void setServiceAppletId(int serviceAppletId) {
94             this.mServiceAppletId = serviceAppletId;
95         }
96 
setServiceAdfOid(@ullable ObjectIdentifier serviceAdfOid)97         public void setServiceAdfOid(@Nullable ObjectIdentifier serviceAdfOid) {
98             this.mServiceAdfOid = Optional.ofNullable(serviceAdfOid);
99         }
100 
getServiceAppletId()101         public int getServiceAppletId() {
102             return mServiceAppletId;
103         }
104 
setSecureBlob(@ullable byte[] secureBlob)105         public void setSecureBlob(@Nullable byte[] secureBlob) {
106             mSecureBlob = Optional.ofNullable(secureBlob);
107         }
108 
getSecureBlob()109         public Optional<byte[]> getSecureBlob() {
110             return mSecureBlob;
111         }
112 
getServiceAdfOid()113         public Optional<ObjectIdentifier> getServiceAdfOid() {
114             return mServiceAdfOid;
115         }
116 
setAdfStatus(int status)117         public void setAdfStatus(int status) {
118             mAdfStatus = status;
119         }
120 
getAdfStatus()121         public int getAdfStatus() {
122             return mAdfStatus;
123         }
124 
125     }
126 
127     /**
128      * Interface define the data source for service config store data.
129      */
130     public interface DataSource {
131         /**
132          * Retrieve the service config list from the data source to serialize them to disk.
133          *
134          * @return Map of package name to {@link ServiceProfileInfo}
135          */
toSerialize()136         Map<UUID, ServiceProfileInfo> toSerialize();
137 
138         /**
139          * Set the service config list in the data source after serializing them from disk.
140          *
141          * @param serviceProfileData Map of package name to {@link ServiceProfileInfo}
142          */
fromDeserialized(Map<UUID, ServiceProfileInfo> serviceProfileData)143         void fromDeserialized(Map<UUID, ServiceProfileInfo> serviceProfileData);
144 
145         /**
146          * Clear internal data structure in preparation for user switch or initial store read.
147          */
reset()148         void reset();
149 
150         /**
151          * Indicates whether there is new data to serialize.
152          */
hasNewDataToSerialize()153         boolean hasNewDataToSerialize();
154     }
155 
156     /**
157      * Data source
158      */
159     private final DataSource mDataSource;
160 
161     /**
162      *
163      * @param builder
164      * Add all service configs to builder so that uwb config store can build and store.
165      */
166     @Override
serializeData(UwbConfigProto.UwbConfig.Builder builder)167     public void serializeData(UwbConfigProto.UwbConfig.Builder builder) {
168         for (Map.Entry<UUID, ServiceProfileInfo> entry : mDataSource.toSerialize().entrySet()) {
169             UwbConfigProto.ServiceConfig.Builder serviceConfigBuilder =
170                     UwbConfigProto.ServiceConfig.newBuilder();
171             ServiceProfileInfo serviceProfileInfo = entry.getValue();
172             serviceConfigBuilder.setServiceInstanceId(serviceProfileInfo
173                     .serviceInstanceID.toString());
174             serviceConfigBuilder.setPackageName(serviceProfileInfo.packageName);
175             serviceConfigBuilder.setUid(serviceProfileInfo.uid);
176             serviceConfigBuilder.setServiceId(serviceProfileInfo.serviceID);
177             serviceConfigBuilder.setServiceAppletId(serviceProfileInfo.getServiceAppletId());
178             serviceConfigBuilder.setAdfStatus(serviceProfileInfo.getAdfStatus());
179             serviceProfileInfo.getServiceAdfOid().ifPresent(
180                     adfOid -> serviceConfigBuilder.setServiceAdfOid(
181                             ByteString.copyFrom(adfOid.value)));
182             serviceProfileInfo.getSecureBlob().ifPresent(
183                     secureBlob -> serviceConfigBuilder.setSecureBlob(
184                             ByteString.copyFrom(secureBlob)));
185             builder.addServiceConfig(serviceConfigBuilder.build());
186         }
187     }
188     /**
189      *
190      * @param uwbConfig
191      * Wrapper to check whether we are using correct version of uwb-config-proto
192      */
193     @Override
deserializeData(@ullable UwbConfigProto.UwbConfig uwbConfig)194     public void deserializeData(@Nullable UwbConfigProto.UwbConfig uwbConfig) {
195         if (uwbConfig == null || !uwbConfig.hasVersion()) {
196             Log.i(LOG_TAG, "No data stored");
197             return;
198         }
199 
200         switch (uwbConfig.getVersion()) {
201             case INITIAL_CONFIG_STORE_DATA_VERSION :
202                 deserializeDataVersion1(uwbConfig);
203                 break;
204             default:
205                 throw new IllegalArgumentException("Unknown Uwb config store version");
206         }
207     }
208 
209     /**
210      * Get all data stored and put it in a map
211      */
deserializeDataVersion1(UwbConfigProto.UwbConfig uwbConfig)212     public void deserializeDataVersion1(UwbConfigProto.UwbConfig uwbConfig) {
213         List<UwbConfigProto.ServiceConfig> serviceConfigList = uwbConfig.getServiceConfigList();
214         Map<UUID, ServiceProfileInfo> serviceProfileDataMap = new HashMap<>();
215         for (UwbConfigProto.ServiceConfig serviceConfig : serviceConfigList) {
216             ServiceProfileInfo serviceProfileInfo = new ServiceProfileInfo(
217                     UUID.fromString(serviceConfig.getServiceInstanceId()),
218                     serviceConfig.getUid(),
219                     serviceConfig.getPackageName(),
220                     serviceConfig.getServiceId());
221             serviceProfileInfo.setServiceAppletId(serviceConfig.getServiceAppletId());
222             serviceProfileInfo.setAdfStatus(serviceConfig.getAdfStatus());
223 
224             serviceProfileInfo.setServiceAdfOid(
225                     ObjectIdentifier.fromBytes(serviceConfig.getServiceAdfOid().toByteArray()));
226 
227             serviceProfileInfo.setSecureBlob(
228                     serviceConfig.getSecureBlob().toByteArray());
229             serviceProfileDataMap.put(serviceProfileInfo.serviceInstanceID, serviceProfileInfo);
230         }
231         mDataSource.fromDeserialized(serviceProfileDataMap);
232     }
233 
234     @Override
resetData()235     public void resetData() {
236         mDataSource.reset();
237     }
238 
239     @Override
hasNewDataToSerialize()240     public boolean hasNewDataToSerialize() {
241         return mDataSource.hasNewDataToSerialize();
242     }
243 
244     @Override
getName()245     public String getName() {
246         return LOG_TAG;
247     }
248 
249     @Override
getStoreFileId()250     public int getStoreFileId() {
251         return STORE_FILE_USER_GENERAL;
252     }
253 }
254