[uwb] Add service profile data to hold to service config

Applet Id and Adf Id can be set later.
Bug: 229410097
Test: Verified manually by implementing profile manager

Change-Id: I680795a343d1b0977f4921131a63565a4a213bea
diff --git a/service/java/com/android/server/uwb/data/ServiceProfileData.java b/service/java/com/android/server/uwb/data/ServiceProfileData.java
new file mode 100644
index 0000000..0459670
--- /dev/null
+++ b/service/java/com/android/server/uwb/data/ServiceProfileData.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.uwb.data;
+
+import static com.android.server.uwb.UwbConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION;
+import static com.android.server.uwb.UwbConfigStore.STORE_FILE_USER_GENERAL;
+
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.server.uwb.UwbConfigStore;
+import com.android.server.uwb.proto.UwbConfigProto;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+public class ServiceProfileData implements UwbConfigStore.StoreData {
+
+    private static String TAG = "ServiceProfileData";
+
+    public ServiceProfileData(DataSource dataSource) {
+        this.mDataSource = dataSource;
+    }
+
+    public static class ServiceProfileInfo {
+        /**
+         * Unique 128-bit service instance ID
+         */
+        public final UUID serviceInstanceID;
+        /**
+         * App uid
+         */
+        public final int uid;
+        /**
+         * App package name
+         */
+        public final String packageName;
+        /**
+         * Service ID, like PACS or custom service
+         */
+        public final int serviceID;
+        /**
+         * Applet ID for dynamic STS
+         */
+        private int serviceAppletID;
+        /**
+         * ADF OID
+         */
+        private int serviceAdfID;
+
+        /**
+         *
+         * serviceAppletID and serviceAdfID will be set after provisioning.
+         */
+        public ServiceProfileInfo(UUID serviceInstanceID, int uid,
+                String packageName, int serviceID) {
+            this.serviceInstanceID = serviceInstanceID;
+            this.uid = uid;
+            this.packageName = packageName;
+            this.serviceID = serviceID;
+        }
+
+        public void setServiceAppletID(int serviceAppletID) {
+            this.serviceAppletID = serviceAppletID;
+        }
+
+        public void setServiceAdfID(int serviceAdfID) {
+            this.serviceAdfID = serviceAdfID;
+        }
+
+        public int getServiceAppletID() {
+            return serviceAppletID;
+        }
+
+        public int getServiceAdfID() {
+            return serviceAdfID;
+        }
+
+    }
+
+    /**
+     * Interface define the data source for service config store data.
+     */
+    public interface DataSource {
+        /**
+         * Retrieve the service config list from the data source to serialize them to disk.
+         *
+         * @return Map of package name to {@link ServiceProfileInfo}
+         */
+        Map<UUID, ServiceProfileInfo> toSerialize();
+
+        /**
+         * Set the service config list in the data source after serializing them from disk.
+         *
+         * @param serviceProfileData Map of package name to {@link ServiceProfileInfo}
+         */
+        void fromDeserialized(Map<UUID, ServiceProfileInfo> serviceProfileData);
+
+        /**
+         * Clear internal data structure in preparation for user switch or initial store read.
+         */
+        void reset();
+
+        /**
+         * Indicates whether there is new data to serialize.
+         */
+        boolean hasNewDataToSerialize();
+    }
+
+    /**
+     * Data source
+     */
+    private final DataSource mDataSource;
+
+    /**
+     *
+     * @param builder
+     * Add all service configs to builder so that uwb config store can build and store.
+     */
+    @Override
+    public void serializeData(UwbConfigProto.UwbConfig.Builder builder) {
+        for (Map.Entry<UUID, ServiceProfileInfo> entry : mDataSource.toSerialize().entrySet()) {
+            UwbConfigProto.ServiceConfig.Builder serviceConfigBuilder =
+                    UwbConfigProto.ServiceConfig.newBuilder();
+            ServiceProfileInfo serviceProfileInfo = entry.getValue();
+            serviceConfigBuilder.setServiceInstanceId(serviceProfileInfo
+                    .serviceInstanceID.toString());
+            serviceConfigBuilder.setPackageName(serviceProfileInfo.packageName);
+            serviceConfigBuilder.setUid(serviceProfileInfo.uid);
+            serviceConfigBuilder.setServiceId(serviceProfileInfo.serviceID);
+            serviceConfigBuilder.setServiceAppletId(serviceProfileInfo.getServiceAppletID());
+            serviceConfigBuilder.setServiceAdfId(serviceProfileInfo.getServiceAdfID());
+            builder.addServiceConfig(serviceConfigBuilder.build());
+        }
+    }
+    /**
+     *
+     * @param uwbConfig
+     * Wrapper to check whether we are using correct version of uwb-config-proto
+     */
+    @Override
+    public void deserializeData(@Nullable UwbConfigProto.UwbConfig uwbConfig) {
+        if (uwbConfig == null || !uwbConfig.hasVersion()) {
+            Log.i(TAG, "No data stored");
+            return;
+        }
+
+        switch (uwbConfig.getVersion()) {
+            case INITIAL_CONFIG_STORE_DATA_VERSION :
+                deserializeDataVersion1(uwbConfig);
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown Uwb config store version");
+        }
+    }
+
+    /**
+     * Get all data stored and put it in a map
+     */
+    public void deserializeDataVersion1(UwbConfigProto.UwbConfig uwbConfig) {
+        List<UwbConfigProto.ServiceConfig> serviceConfigList = uwbConfig.getServiceConfigList();
+        Map<UUID, ServiceProfileInfo> serviceProfileDataMap = new HashMap<>();
+        for (UwbConfigProto.ServiceConfig serviceConfig : serviceConfigList) {
+            ServiceProfileInfo serviceProfileInfo = new ServiceProfileInfo(
+                    UUID.fromString(serviceConfig.getServiceInstanceId()),
+                    serviceConfig.getUid(),
+                    serviceConfig.getPackageName(),
+                    serviceConfig.getServiceId());
+            serviceProfileInfo.setServiceAppletID(serviceConfig.getServiceAppletId());
+            serviceProfileInfo.setServiceAdfID(serviceConfig.getServiceAdfId());
+            serviceProfileDataMap.put(serviceProfileInfo.serviceInstanceID, serviceProfileInfo);
+        }
+        mDataSource.fromDeserialized(serviceProfileDataMap);
+    }
+
+    @Override
+    public void resetData() {
+        mDataSource.reset();
+    }
+
+    @Override
+    public boolean hasNewDataToSerialize() {
+        return mDataSource.hasNewDataToSerialize();
+    }
+
+    @Override
+    public String getName() {
+        return TAG;
+    }
+
+    @Override
+    public int getStoreFileId() {
+        return STORE_FILE_USER_GENERAL;
+    }
+}
diff --git a/service/tests/src/com/android/server/uwb/data/ServiceProfileDataTest.java b/service/tests/src/com/android/server/uwb/data/ServiceProfileDataTest.java
new file mode 100644
index 0000000..56af428
--- /dev/null
+++ b/service/tests/src/com/android/server/uwb/data/ServiceProfileDataTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.uwb.data;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.uwb.data.ServiceProfileData.ServiceProfileInfo;
+import com.android.server.uwb.proto.UwbConfigProto;
+
+import com.google.protobuf.InvalidProtocolBufferException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@Presubmit
+public class ServiceProfileDataTest {
+    private MockDataSource mDataSource;
+    private ServiceProfileData mServiceProfileData;
+
+    @Before
+    public void setUp() {
+        mDataSource = new MockDataSource();
+        mServiceProfileData = new ServiceProfileData(mDataSource);
+    }
+
+    @Test
+    public void testSerializeData() {
+        UwbConfigProto.UwbConfig.Builder builder = UwbConfigProto.UwbConfig.newBuilder();
+        builder.setVersion(1);
+        mServiceProfileData.serializeData(builder);
+
+        UwbConfigProto.ServiceConfig serviceConfig = builder.getServiceConfig(0);
+        UUID serviceInstanceID = new UUID(100, 500);
+
+        assertEquals(serviceConfig.getServiceId(), 1);
+        assertEquals(serviceConfig.getServiceInstanceId(), serviceInstanceID);
+        assertEquals(serviceConfig.getUid(), 1);
+        assertEquals(serviceConfig.getPackageName(), "test");
+
+    }
+
+    @Test
+    public void testDeserializeData() throws InvalidProtocolBufferException {
+        UwbConfigProto.UwbConfig.Builder builder = UwbConfigProto.UwbConfig.newBuilder();
+        builder.setVersion(1);
+        mServiceProfileData.serializeData(builder);
+        byte[] dataBytes = builder.build().toByteArray();
+        UwbConfigProto.UwbConfig uwbConfig = UwbConfigProto.UwbConfig.parseFrom(dataBytes);
+
+        mServiceProfileData.deserializeData(uwbConfig);
+        assertTrue(mDataSource.mData.size() == 1);
+
+        mServiceProfileData.resetData();
+        assertTrue(mDataSource.mData == null);
+
+        assertTrue(mServiceProfileData.hasNewDataToSerialize());
+
+        assertEquals(mServiceProfileData.getName(), "ServiceProfileData");
+
+        assertEquals(mServiceProfileData.getStoreFileId(), 1);
+    }
+
+    private static class MockDataSource implements ServiceProfileData.DataSource {
+
+        public Map<UUID, ServiceProfileData.ServiceProfileInfo> mData =
+                new HashMap<>();
+        @Override
+        public Map<UUID, ServiceProfileInfo> toSerialize() {
+            Map<UUID, ServiceProfileInfo> mServiceProfileMap =
+                    new HashMap<>();
+            UUID serviceInstanceID = new UUID(100, 500);
+            int uid = 1;
+            String packageName = "test";
+            int serviceID = 1;
+            ServiceProfileInfo mServiceProfileInfo =
+                    new ServiceProfileInfo(serviceInstanceID, uid, packageName, serviceID);
+            mServiceProfileMap.put(serviceInstanceID, mServiceProfileInfo);
+            return mServiceProfileMap;
+        }
+
+        @Override
+        public void fromDeserialized(
+                Map<UUID, ServiceProfileData.ServiceProfileInfo> serviceProfileData) {
+            mData = serviceProfileData;
+        }
+
+        @Override
+        public void reset() {
+            mData = null;
+        }
+
+        @Override
+        public boolean hasNewDataToSerialize() {
+            return true;
+        }
+    }
+}