Home | History | Annotate | Download | only in location
      1 /*
      2  * Copyright 2017 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.location;
     18 
     19 import android.annotation.Nullable;
     20 import android.hardware.contexthub.V1_0.HubAppInfo;
     21 import android.hardware.location.NanoAppInstanceInfo;
     22 import android.util.Log;
     23 
     24 import java.util.Collection;
     25 import java.util.HashMap;
     26 import java.util.HashSet;
     27 import java.util.Iterator;
     28 import java.util.List;
     29 
     30 /**
     31  * Manages the state of loaded nanoapps at the Context Hubs.
     32  *
     33  * This class maintains a list of nanoapps that have been informed as loaded at the hubs. The state
     34  * should be updated based on the hub callbacks (defined in IContexthubCallback.hal), as a result
     35  * of either loadNanoApp, unloadNanoApp, or queryApps.
     36  *
     37  * The state tracked by this manager is used by clients of ContextHubService that use the old APIs.
     38  *
     39  * TODO(b/69270990): Remove this class and its logic once the old API is deprecated.
     40  *
     41  * @hide
     42  */
     43 /* package */ class NanoAppStateManager {
     44     private static final String TAG = "NanoAppStateManager";
     45 
     46     /*
     47      * Enables verbose debug logs for this class.
     48      */
     49     private static final boolean ENABLE_LOG_DEBUG = true;
     50 
     51     /*
     52      * Service cache maintaining of handle to nanoapp infos.
     53      */
     54     private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
     55 
     56     /*
     57      * The next nanoapp handle to use.
     58      */
     59     private int mNextHandle = 0;
     60 
     61     /**
     62      * @param nanoAppHandle the nanoapp handle
     63      * @return the NanoAppInstanceInfo for the given nanoapp, or null if the nanoapp does not exist
     64      *         in the cache
     65      */
     66     @Nullable
     67     /* package */
     68     synchronized NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
     69         return mNanoAppHash.get(nanoAppHandle);
     70     }
     71 
     72     /**
     73      * @return a collection of NanoAppInstanceInfo objects in the cache
     74      */
     75     /* package */
     76     synchronized Collection<NanoAppInstanceInfo> getNanoAppInstanceInfoCollection() {
     77         return mNanoAppHash.values();
     78     }
     79 
     80     /**
     81      * @param contextHubId the ID of the hub to search for the instance
     82      * @param nanoAppId the unique 64-bit ID of the nanoapp
     83      * @return the nanoapp handle, -1 if the nanoapp is not in the cache
     84      */
     85     /* package */
     86     synchronized int getNanoAppHandle(int contextHubId, long nanoAppId) {
     87         for (NanoAppInstanceInfo info : mNanoAppHash.values()) {
     88             if (info.getContexthubId() == contextHubId && info.getAppId() == nanoAppId) {
     89                 return info.getHandle();
     90             }
     91         }
     92 
     93         return -1;
     94     }
     95 
     96     /**
     97      * Adds a nanoapp instance to the cache.
     98      *
     99      * If the cache already contained the nanoapp, the entry is removed and a new nanoapp handle is
    100      * generated.
    101      *
    102      * @param contextHubId the ID of the hub the nanoapp is loaded in
    103      * @param nanoAppId the unique 64-bit ID of the nanoapp
    104      * @param nanoAppVersion the version of the nanoapp
    105      */
    106     /* package */
    107     synchronized void addNanoAppInstance(int contextHubId, long nanoAppId, int nanoAppVersion) {
    108         removeNanoAppInstance(contextHubId, nanoAppId);
    109         if (mNanoAppHash.size() == Integer.MAX_VALUE) {
    110             Log.e(TAG, "Error adding nanoapp instance: max limit exceeded");
    111             return;
    112         }
    113 
    114         int nanoAppHandle = mNextHandle;
    115         for (int i = 0; i <= Integer.MAX_VALUE; i++) {
    116             if (!mNanoAppHash.containsKey(nanoAppHandle)) {
    117                 mNanoAppHash.put(nanoAppHandle, new NanoAppInstanceInfo(
    118                         nanoAppHandle, nanoAppId, nanoAppVersion, contextHubId));
    119                 mNextHandle = (nanoAppHandle == Integer.MAX_VALUE) ? 0 : nanoAppHandle + 1;
    120                 break;
    121             }
    122             nanoAppHandle = (nanoAppHandle == Integer.MAX_VALUE) ? 0 : nanoAppHandle + 1;
    123         }
    124 
    125         if (ENABLE_LOG_DEBUG) {
    126             Log.v(TAG, "Added app instance with handle " + nanoAppHandle + " to hub "
    127                     + contextHubId + ": ID=0x" + Long.toHexString(nanoAppId)
    128                     + ", version=0x" + Integer.toHexString(nanoAppVersion));
    129         }
    130     }
    131 
    132     /**
    133      * Removes a nanoapp instance from the cache.
    134      *
    135      * @param nanoAppId the ID of the nanoapp to remove the instance of
    136      */
    137     /* package */
    138     synchronized void removeNanoAppInstance(int contextHubId, long nanoAppId) {
    139         int nanoAppHandle = getNanoAppHandle(contextHubId, nanoAppId);
    140         mNanoAppHash.remove(nanoAppHandle);
    141     }
    142 
    143     /**
    144      * Performs a batch update of the nanoapp cache given a nanoapp query response.
    145      *
    146      * @param contextHubId    the ID of the hub the response came from
    147      * @param nanoAppInfoList the list of loaded nanoapps
    148      */
    149     /* package */
    150     synchronized void updateCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
    151         HashSet<Long> nanoAppIdSet = new HashSet<>();
    152         for (HubAppInfo appInfo : nanoAppInfoList) {
    153             handleQueryAppEntry(contextHubId, appInfo.appId, appInfo.version);
    154             nanoAppIdSet.add(appInfo.appId);
    155         }
    156 
    157         Iterator<NanoAppInstanceInfo> iterator = mNanoAppHash.values().iterator();
    158         while (iterator.hasNext()) {
    159             NanoAppInstanceInfo info = iterator.next();
    160             if (info.getContexthubId() == contextHubId &&
    161                     !nanoAppIdSet.contains(info.getAppId())) {
    162                 iterator.remove();
    163             }
    164         }
    165     }
    166 
    167     /**
    168      * If the nanoapp exists in the cache, then the entry is updated. Otherwise, inserts a new
    169      * instance of the nanoapp in the cache. This method should only be invoked from updateCache.
    170      *
    171      * @param contextHubId the ID of the hub the nanoapp is loaded in
    172      * @param nanoAppId the unique 64-bit ID of the nanoapp
    173      * @param nanoAppVersion the version of the nanoapp
    174      */
    175     private void handleQueryAppEntry(int contextHubId, long nanoAppId, int nanoAppVersion) {
    176         int nanoAppHandle = getNanoAppHandle(contextHubId, nanoAppId);
    177         if (nanoAppHandle == -1) {
    178             addNanoAppInstance(contextHubId, nanoAppId, nanoAppVersion);
    179         } else {
    180             NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppHandle);
    181             if (info.getAppVersion() != nanoAppVersion) {
    182                 mNanoAppHash.put(nanoAppHandle, new NanoAppInstanceInfo(
    183                         nanoAppHandle, nanoAppId, nanoAppVersion, contextHubId));
    184                 if (ENABLE_LOG_DEBUG) {
    185                     Log.v(TAG, "Updated app instance with handle " + nanoAppHandle + " at hub "
    186                             + contextHubId + ": ID=0x" + Long.toHexString(nanoAppId)
    187                             + ", version=0x" + Integer.toHexString(nanoAppVersion));
    188                 }
    189             }
    190         }
    191     }
    192 }
    193