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