blob: 91b796aba65509cf7a6e65390c3e5e02d024e013 [file] [log] [blame]
Yifan Hong8ef5fead2017-03-27 13:02: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 android.os;
18
Steven Morelande8e63aa2018-01-10 15:45:36 -080019import android.annotation.SystemApi;
20
Yifan Hong8ef5fead2017-03-27 13:02:34 -070021import java.util.Arrays;
22import java.util.Collection;
23import java.util.Iterator;
24import java.util.List;
25import java.util.Map;
26import java.util.Objects;
27import java.util.stream.IntStream;
28
29/** @hide */
Steven Morelande8e63aa2018-01-10 15:45:36 -080030@SystemApi
Yifan Hong8ef5fead2017-03-27 13:02:34 -070031public class HidlSupport {
32 /**
33 * Similar to Objects.deepEquals, but also take care of lists.
34 * Two objects of HIDL types are considered equal if:
35 * 1. Both null
36 * 2. Both non-null, and of the same class, and:
37 * 2.1 Both are primitive arrays / enum arrays, elements are equal using == check
38 * 2.2 Both are object arrays, elements are checked recursively
39 * 2.3 Both are Lists, elements are checked recursively
40 * 2.4 (If both are collections other than lists or maps, throw an error)
41 * 2.5 lft.equals(rgt) returns true
Steven Morelande8e63aa2018-01-10 15:45:36 -080042 * @hide
Yifan Hong8ef5fead2017-03-27 13:02:34 -070043 */
Steven Morelande8e63aa2018-01-10 15:45:36 -080044 @SystemApi
Yifan Hong8ef5fead2017-03-27 13:02:34 -070045 public static boolean deepEquals(Object lft, Object rgt) {
46 if (lft == rgt) {
47 return true;
48 }
49 if (lft == null || rgt == null) {
50 return false;
51 }
52
53 Class<?> lftClazz = lft.getClass();
54 Class<?> rgtClazz = rgt.getClass();
55 if (lftClazz != rgtClazz) {
56 return false;
57 }
58
59 if (lftClazz.isArray()) {
60 Class<?> lftElementType = lftClazz.getComponentType();
61 if (lftElementType != rgtClazz.getComponentType()) {
62 return false;
63 }
64
65 if (lftElementType.isPrimitive()) {
66 return Objects.deepEquals(lft, rgt);
67 }
68
69 Object[] lftArray = (Object[])lft;
70 Object[] rgtArray = (Object[])rgt;
71 return (lftArray.length == rgtArray.length) &&
72 IntStream.range(0, lftArray.length).allMatch(
73 i -> deepEquals(lftArray[i], rgtArray[i]));
74 }
75
76 if (lft instanceof List<?>) {
77 List<Object> lftList = (List<Object>)lft;
78 List<Object> rgtList = (List<Object>)rgt;
79 if (lftList.size() != rgtList.size()) {
80 return false;
81 }
82
83 Iterator<Object> lftIter = lftList.iterator();
84 return rgtList.stream()
85 .allMatch(rgtElement -> deepEquals(lftIter.next(), rgtElement));
86 }
87
88 throwErrorIfUnsupportedType(lft);
89
90 return lft.equals(rgt);
91 }
92
93 /**
Steven Moreland4bfa2eb2018-01-05 09:41:10 -080094 * Class which can be used to fetch an object out of a lambda. Fetching an object
95 * out of a local scope with HIDL is a common operation (although usually it can
96 * and should be avoided).
97 *
98 * @param <E> Inner object type.
Steven Morelande8e63aa2018-01-10 15:45:36 -080099 * @hide
Steven Moreland4bfa2eb2018-01-05 09:41:10 -0800100 */
101 public static final class Mutable<E> {
102 public E value;
103
104 public Mutable() {
105 value = null;
106 }
107
108 public Mutable(E value) {
109 this.value = value;
110 }
111 }
112
113 /**
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700114 * Similar to Arrays.deepHashCode, but also take care of lists.
Steven Morelande8e63aa2018-01-10 15:45:36 -0800115 * @hide
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700116 */
Steven Morelande8e63aa2018-01-10 15:45:36 -0800117 @SystemApi
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700118 public static int deepHashCode(Object o) {
119 if (o == null) {
120 return 0;
121 }
122 Class<?> clazz = o.getClass();
123 if (clazz.isArray()) {
124 Class<?> elementType = clazz.getComponentType();
125 if (elementType.isPrimitive()) {
126 return primitiveArrayHashCode(o);
127 }
128 return Arrays.hashCode(Arrays.stream((Object[])o)
129 .mapToInt(element -> deepHashCode(element))
130 .toArray());
131 }
132
133 if (o instanceof List<?>) {
134 return Arrays.hashCode(((List<Object>)o).stream()
135 .mapToInt(element -> deepHashCode(element))
136 .toArray());
137 }
138
139 throwErrorIfUnsupportedType(o);
140
141 return o.hashCode();
142 }
143
Steven Morelande8e63aa2018-01-10 15:45:36 -0800144 /** @hide */
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700145 private static void throwErrorIfUnsupportedType(Object o) {
146 if (o instanceof Collection<?> && !(o instanceof List<?>)) {
147 throw new UnsupportedOperationException(
148 "Cannot check equality on collections other than lists: " +
149 o.getClass().getName());
150 }
151
152 if (o instanceof Map<?, ?>) {
153 throw new UnsupportedOperationException(
154 "Cannot check equality on maps");
155 }
156 }
157
Steven Morelande8e63aa2018-01-10 15:45:36 -0800158 /** @hide */
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700159 private static int primitiveArrayHashCode(Object o) {
160 Class<?> elementType = o.getClass().getComponentType();
161 if (elementType == boolean.class) {
162 return Arrays.hashCode(((boolean[])o));
163 }
164 if (elementType == byte.class) {
165 return Arrays.hashCode(((byte[])o));
166 }
167 if (elementType == char.class) {
168 return Arrays.hashCode(((char[])o));
169 }
170 if (elementType == double.class) {
171 return Arrays.hashCode(((double[])o));
172 }
173 if (elementType == float.class) {
174 return Arrays.hashCode(((float[])o));
175 }
176 if (elementType == int.class) {
177 return Arrays.hashCode(((int[])o));
178 }
179 if (elementType == long.class) {
180 return Arrays.hashCode(((long[])o));
181 }
182 if (elementType == short.class) {
183 return Arrays.hashCode(((short[])o));
184 }
185 // Should not reach here.
186 throw new UnsupportedOperationException();
187 }
Yifan Hong73b6c272017-10-31 17:32:15 -0700188
189 /**
190 * Test that two interfaces are equal. This is the Java equivalent to C++
191 * interfacesEqual function.
192 * This essentially calls .equals on the internal binder objects (via Binder()).
193 * - If both interfaces are proxies, asBinder() returns a {@link HwRemoteBinder}
194 * object, and they are compared in {@link HwRemoteBinder#equals}.
195 * - If both interfaces are stubs, asBinder() returns the object itself. By default,
196 * auto-generated IFoo.Stub does not override equals(), but an implementation can
197 * optionally override it, and {@code interfacesEqual} will use it here.
Steven Morelande8e63aa2018-01-10 15:45:36 -0800198 * @hide
Yifan Hong73b6c272017-10-31 17:32:15 -0700199 */
Steven Morelande8e63aa2018-01-10 15:45:36 -0800200 @SystemApi
Yifan Hong73b6c272017-10-31 17:32:15 -0700201 public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
202 if (lft == rgt) {
203 return true;
204 }
205 if (lft == null || rgt == null) {
206 return false;
207 }
208 if (!(rgt instanceof IHwInterface)) {
209 return false;
210 }
211 return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
212 }
Yifan Hongbb0bd002017-11-14 16:14:04 -0800213
214 /**
Steven Morelandadcb8962018-01-25 10:24:07 -0800215 * Return PID of process only if on a non-user build. For debugging purposes.
Steven Morelande8e63aa2018-01-10 15:45:36 -0800216 * @hide
Yifan Hongbb0bd002017-11-14 16:14:04 -0800217 */
Steven Morelandadcb8962018-01-25 10:24:07 -0800218 @SystemApi
Yifan Hongbb0bd002017-11-14 16:14:04 -0800219 public static native int getPidIfSharable();
Steven Morelande8e63aa2018-01-10 15:45:36 -0800220
221 /** @hide */
222 public HidlSupport() {}
Yifan Hong8ef5fead2017-03-27 13:02:34 -0700223}