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