1 /* 2 * Copyright (C) 2020 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.vms; 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 * 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 44 class VmsLayerAvailability { 45 private static final boolean DBG = false; 46 private static final String TAG = VmsLayerAvailability.class.getSimpleName(); 47 48 private final Object mLock = new Object(); 49 @GuardedBy("mLock") 50 private final Map<VmsLayer, Set<Set<VmsLayer>>> mPotentialLayersAndDependencies = 51 new HashMap<>(); 52 @GuardedBy("mLock") 53 private Set<VmsAssociatedLayer> mAvailableAssociatedLayers = Collections.emptySet(); 54 @GuardedBy("mLock") 55 private Map<VmsLayer, Set<Integer>> mPotentialLayersAndPublishers = new HashMap<>(); 56 @GuardedBy("mLock") 57 private int mSeq = 0; 58 59 /** 60 * Setting the current layers offerings as reported by publishers. 61 */ setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings)62 void setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings) { 63 synchronized (mLock) { 64 reset(); 65 66 for (VmsLayersOffering offering : publishersLayersOfferings) { 67 for (VmsLayerDependency dependency : offering.getDependencies()) { 68 VmsLayer layer = dependency.getLayer(); 69 70 // Associate publishers with layers. 71 mPotentialLayersAndPublishers.computeIfAbsent(layer, k -> new HashSet<>()) 72 .add(offering.getPublisherId()); 73 74 // Add dependencies for availability calculation. 75 mPotentialLayersAndDependencies.computeIfAbsent(layer, k -> new HashSet<>()) 76 .add(dependency.getDependencies()); 77 } 78 } 79 calculateLayers(); 80 } 81 } 82 83 /** 84 * Returns a collection of all the layers which may be published. 85 */ getAvailableLayers()86 VmsAvailableLayers getAvailableLayers() { 87 synchronized (mLock) { 88 return new VmsAvailableLayers(mAvailableAssociatedLayers, mSeq); 89 } 90 } 91 reset()92 private void reset() { 93 synchronized (mLock) { 94 mPotentialLayersAndDependencies.clear(); 95 mPotentialLayersAndPublishers.clear(); 96 mAvailableAssociatedLayers = Collections.emptySet(); 97 mSeq += 1; 98 } 99 } 100 calculateLayers()101 private void calculateLayers() { 102 synchronized (mLock) { 103 Set<VmsLayer> availableLayersSet = new HashSet<>(); 104 Set<VmsLayer> cyclicAvoidanceAuxiliarySet = new HashSet<>(); 105 106 for (VmsLayer layer : mPotentialLayersAndDependencies.keySet()) { 107 addLayerToAvailabilityCalculationLocked(layer, 108 availableLayersSet, 109 cyclicAvoidanceAuxiliarySet); 110 } 111 112 mAvailableAssociatedLayers = Collections.unmodifiableSet( 113 availableLayersSet 114 .stream() 115 .map(l -> new VmsAssociatedLayer(l, 116 mPotentialLayersAndPublishers.get(l))) 117 .collect(Collectors.toSet())); 118 } 119 } 120 121 @GuardedBy("mLock") addLayerToAvailabilityCalculationLocked(VmsLayer layer, Set<VmsLayer> currentAvailableLayers, Set<VmsLayer> cyclicAvoidanceSet)122 private void addLayerToAvailabilityCalculationLocked(VmsLayer layer, 123 Set<VmsLayer> currentAvailableLayers, 124 Set<VmsLayer> cyclicAvoidanceSet) { 125 if (DBG) { 126 Log.d(TAG, "addLayerToAvailabilityCalculationLocked: checking layer: " + layer); 127 } 128 // If we already know that this layer is supported then we are done. 129 if (currentAvailableLayers.contains(layer)) { 130 return; 131 } 132 // If there is no offering for this layer we're done. 133 if (!mPotentialLayersAndDependencies.containsKey(layer)) { 134 return; 135 } 136 // Avoid cyclic dependency. 137 if (cyclicAvoidanceSet.contains(layer)) { 138 Log.e(TAG, "Detected a cyclic dependency: " + cyclicAvoidanceSet + " -> " + layer); 139 return; 140 } 141 // A layer may have multiple dependency sets. The layer is available if any dependency 142 // set is satisfied 143 for (Set<VmsLayer> dependencies : mPotentialLayersAndDependencies.get(layer)) { 144 // If layer does not have any dependencies then add to supported. 145 if (dependencies == null || dependencies.isEmpty()) { 146 currentAvailableLayers.add(layer); 147 return; 148 } 149 // Add the layer to cyclic avoidance set 150 cyclicAvoidanceSet.add(layer); 151 152 boolean isSupported = true; 153 for (VmsLayer dependency : dependencies) { 154 addLayerToAvailabilityCalculationLocked(dependency, 155 currentAvailableLayers, 156 cyclicAvoidanceSet); 157 158 if (!currentAvailableLayers.contains(dependency)) { 159 isSupported = false; 160 break; 161 } 162 } 163 cyclicAvoidanceSet.remove(layer); 164 165 if (isSupported) { 166 currentAvailableLayers.add(layer); 167 return; 168 } 169 } 170 } 171 } 172