1 /*
2  * Copyright (C) 2014 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 package android.hardware.camera2.marshal;
17 
18 import android.annotation.Nullable;
19 import android.hardware.camera2.impl.CameraMetadataNative;
20 import android.hardware.camera2.utils.TypeReference;
21 
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 
26 /**
27  * Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
28  */
29 public class MarshalRegistry {
30 
31     /**
32      * Register a marshal queryable for the managed type {@code T}.
33      *
34      * <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
35      * this is desirable if they support different native types (e.g. marshaler 1 supports
36      * {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
37      *
38      * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
39      */
registerMarshalQueryable(MarshalQueryable<T> queryable)40     public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
41         synchronized(sMarshalLock) {
42             sRegisteredMarshalQueryables.add(queryable);
43         }
44     }
45 
46     /**
47      * Lookup a marshaler between {@code T} and {@code nativeType}.
48      *
49      * <p>Marshalers are looked up in the order they were registered; earlier registered
50      * marshal queriers get priority.</p>
51      *
52      * @param typeToken The compile-time type reference for {@code T}
53      * @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
54      * @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
55      *
56      * @throws UnsupportedOperationException If no marshaler matching the args could be found
57      */
58     @SuppressWarnings("unchecked")
getMarshaler(TypeReference<T> typeToken, int nativeType)59     public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
60         synchronized(sMarshalLock) {
61             // TODO: can avoid making a new token each time by code-genning
62             // the list of type tokens and native types from the keys (at the call sites)
63             MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
64 
65             /*
66              * Marshalers are instantiated lazily once they are looked up; successive lookups
67              * will not instantiate new marshalers.
68              */
69             Marshaler<T> marshaler =
70                     (Marshaler<T>) sMarshalerMap.get(marshalToken);
71 
72             if (marshaler == null) {
73 
74                 if (sRegisteredMarshalQueryables.size() == 0) {
75                     throw new AssertionError("No available query marshalers registered");
76                 }
77 
78                 // Query each marshaler to see if they support the native/managed type combination
79                 for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
80 
81                     MarshalQueryable<T> castedPotential =
82                             (MarshalQueryable<T>)potentialMarshaler;
83 
84                     if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
85                         marshaler = castedPotential.createMarshaler(typeToken, nativeType);
86                         break;
87                     }
88                 }
89 
90                 if (marshaler == null) {
91                     throw new UnsupportedOperationException(
92                         "Could not find marshaler that matches the requested " +
93                         "combination of type reference " +
94                         typeToken + " and native type " +
95                         MarshalHelpers.toStringNativeType(nativeType));
96                 }
97 
98                 // Only put when no cached version exists to avoid +0.5ms lookup per call.
99                 sMarshalerMap.put(marshalToken, marshaler);
100             }
101 
102             return marshaler;
103         }
104     }
105 
106     private static class MarshalToken<T> {
MarshalToken(TypeReference<T> typeReference, int nativeType)107         public MarshalToken(TypeReference<T> typeReference, int nativeType) {
108             this.typeReference = typeReference;
109             this.nativeType = nativeType;
110             this.hash = typeReference.hashCode() ^ nativeType;
111         }
112 
113         final TypeReference<T> typeReference;
114         final int nativeType;
115         private final int hash;
116 
117         @Override
equals(@ullable Object other)118         public boolean equals(@Nullable Object other) {
119             if (other instanceof MarshalToken<?>) {
120                 MarshalToken<?> otherToken = (MarshalToken<?>)other;
121                 return typeReference.equals(otherToken.typeReference) &&
122                         nativeType == otherToken.nativeType;
123             }
124 
125             return false;
126         }
127 
128         @Override
hashCode()129         public int hashCode() {
130             return hash;
131         }
132     }
133 
134     // Control access to the static data structures below
135     private static final Object sMarshalLock = new Object();
136 
137     private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
138             new ArrayList<MarshalQueryable<?>>();
139     private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
140             new HashMap<MarshalToken<?>, Marshaler<?>>();
141 
MarshalRegistry()142     private MarshalRegistry() {
143         throw new AssertionError();
144     }
145 }
146