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 */ setPublishersOffering(Collection<VmsLayersOffering> publishersLayersOfferings)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 */ getAvailableLayers()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 */ getUnavailableLayers()96 public Collection<VmsLayer> getUnavailableLayers() { 97 synchronized (mLock) { 98 return mUnavailableLayers; 99 } 100 } 101 reset()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 calculateLayers()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 isLayerSupportedLocked(VmsLayer layer, Set<VmsLayer> currentAvailableLayers)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