Home | History | Annotate | Download | only in car
      1 /*
      2  * Copyright (C) 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.car;
     18 
     19 import android.car.annotation.FutureFeature;
     20 import android.car.vms.VmsLayer;
     21 import android.car.vms.VmsLayerDependency;
     22 import android.car.vms.VmsLayersOffering;
     23 import android.util.Log;
     24 import com.android.internal.annotations.GuardedBy;
     25 import java.util.ArrayList;
     26 import java.util.Collection;
     27 import java.util.Collections;
     28 import java.util.HashMap;
     29 import java.util.HashSet;
     30 import java.util.List;
     31 import java.util.Map;
     32 import java.util.Set;
     33 import java.util.stream.Collectors;
     34 
     35 /**
     36  * Manages VMS availability for layers.
     37  *
     38  * Each VMS publisher sets its layers offering which are a list of layers the publisher claims
     39  * it might publish. VmsLayersAvailability calculates from all the offering what are the
     40  * available layers.
     41  */
     42 
     43 @FutureFeature
     44 public class VmsLayersAvailability {
     45 
     46     private static final boolean DBG = true;
     47     private static final String TAG = "VmsLayersAvailability";
     48 
     49     private final Object mLock = new Object();
     50     @GuardedBy("mLock")
     51     private final Map<VmsLayer, Set<Set<VmsLayer>>> mPotentialLayersAndDependencies =
     52         new HashMap<>();
     53     @GuardedBy("mLock")
     54     private final Set<VmsLayer> mCyclicAvoidanceSet = new HashSet<>();
     55     @GuardedBy("mLock")
     56     private Set<VmsLayer> mAvailableLayers = Collections.EMPTY_SET;
     57     @GuardedBy("mLock")
     58     private Set<VmsLayer> mUnavailableLayers = Collections.EMPTY_SET;
     59 
     60     /**
     61      * Setting the current layers offerings as reported by publishers.
     62      */
     63     public void setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings) {
     64         synchronized (mLock) {
     65             reset();
     66 
     67             for (VmsLayersOffering offering : publishersLayersOfferings) {
     68                 for (VmsLayerDependency dependency : offering.getDependencies()) {
     69                     VmsLayer layer = dependency.getLayer();
     70                     Set<Set<VmsLayer>> curDependencies =
     71                         mPotentialLayersAndDependencies.get(layer);
     72                     if (curDependencies == null) {
     73                         curDependencies = new HashSet<>();
     74                         mPotentialLayersAndDependencies.put(layer, curDependencies);
     75                     }
     76                     curDependencies.add(dependency.getDependencies());
     77                 }
     78             }
     79             calculateLayers();
     80         }
     81     }
     82 
     83     /**
     84      * Returns a collection of all the layers which may be published.
     85      */
     86     public Collection<VmsLayer> getAvailableLayers() {
     87         synchronized (mLock) {
     88             return mAvailableLayers;
     89         }
     90     }
     91 
     92     /**
     93      * Returns a collection of all the layers which publishers could have published if the
     94      * dependencies were satisfied.
     95      */
     96     public Collection<VmsLayer> getUnavailableLayers() {
     97         synchronized (mLock) {
     98             return mUnavailableLayers;
     99         }
    100     }
    101 
    102     private void reset() {
    103         synchronized (mLock) {
    104             mCyclicAvoidanceSet.clear();
    105             mPotentialLayersAndDependencies.clear();
    106             mAvailableLayers = Collections.EMPTY_SET;
    107             mUnavailableLayers = Collections.EMPTY_SET;
    108         }
    109     }
    110 
    111     private void calculateLayers() {
    112         synchronized (mLock) {
    113             final Set<VmsLayer> availableLayers = new HashSet<>();
    114 
    115             availableLayers.addAll(
    116                 mPotentialLayersAndDependencies.keySet()
    117                     .stream()
    118                     .filter(layer -> isLayerSupportedLocked(layer, availableLayers))
    119                     .collect(Collectors.toSet()));
    120 
    121             mAvailableLayers = Collections.unmodifiableSet(availableLayers);
    122             mUnavailableLayers = Collections.unmodifiableSet(
    123                 mPotentialLayersAndDependencies.keySet()
    124                     .stream()
    125                     .filter(layer -> !availableLayers.contains(layer))
    126                     .collect(Collectors.toSet()));
    127         }
    128     }
    129 
    130     private boolean isLayerSupportedLocked(VmsLayer layer, Set<VmsLayer> currentAvailableLayers) {
    131         if (DBG) {
    132             Log.d(TAG, "isLayerSupported: checking layer: " + layer);
    133         }
    134         // If we already know that this layer is supported then we are done.
    135         if (currentAvailableLayers.contains(layer)) {
    136             return true;
    137         }
    138         // If there is no offering for this layer we're done.
    139         if (!mPotentialLayersAndDependencies.containsKey(layer)) {
    140             return false;
    141         }
    142         // Avoid cyclic dependency.
    143         if (mCyclicAvoidanceSet.contains(layer)) {
    144             Log.e(TAG, "Detected a cyclic dependency: " + mCyclicAvoidanceSet + " -> " + layer);
    145             return false;
    146         }
    147         for (Set<VmsLayer> dependencies : mPotentialLayersAndDependencies.get(layer)) {
    148             // If layer does not have any dependencies then add to supported.
    149             if (dependencies == null || dependencies.isEmpty()) {
    150                 currentAvailableLayers.add(layer);
    151                 return true;
    152             }
    153             // Add the layer to cyclic avoidance set
    154             mCyclicAvoidanceSet.add(layer);
    155 
    156             boolean isSupported = true;
    157             for (VmsLayer dependency : dependencies) {
    158                 if (!isLayerSupportedLocked(dependency, currentAvailableLayers)) {
    159                     isSupported = false;
    160                     break;
    161                 }
    162             }
    163             mCyclicAvoidanceSet.remove(layer);
    164 
    165             if (isSupported) {
    166                 currentAvailableLayers.add(layer);
    167                 return true;
    168             }
    169         }
    170         return false;
    171     }
    172 }
    173