blob: 5f5ac3085e904b9b91a5921d721f0da845cab7ef [file] [log] [blame]
Asaf Rosenfelda5dfba12017-03-23 13:18:34 -07001/*
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
17package com.android.car;
18
19import android.car.annotation.FutureFeature;
20import android.car.vms.VmsLayer;
21import android.car.vms.VmsLayerDependency;
22import android.car.vms.VmsLayersOffering;
23import android.util.Log;
24import com.android.internal.annotations.GuardedBy;
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Collections;
28import java.util.HashMap;
29import java.util.HashSet;
30import java.util.List;
31import java.util.Map;
32import java.util.Set;
33import 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
44public 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}