blob: b311a92956caca37527c89d0c9acbb049a012f65 [file] [log] [blame]
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -07001/*
2 * Copyright 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 */
16package android.hardware.location;
17
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080018import android.annotation.SystemApi;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070019import android.os.Parcel;
20import android.os.Parcelable;
21import android.util.Log;
22
23import java.nio.BufferUnderflowException;
24import java.nio.ByteBuffer;
25import java.nio.ByteOrder;
Arthur Ishiguro0d719c22017-10-30 16:41:40 -070026import java.util.Arrays;
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070027
28/**
29 * @hide
30 */
Arthur Ishigurof2b6f012017-11-28 15:21:38 -080031@SystemApi
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070032public final class NanoAppBinary implements Parcelable {
33 private static final String TAG = "NanoAppBinary";
34
35 /*
36 * The contents of the app binary.
37 */
38 private byte[] mNanoAppBinary;
39
40 /*
41 * Contents of the nanoapp binary header.
42 *
43 * Only valid if mHasValidHeader is true.
44 * See nano_app_binary_t in context_hub.h for details.
45 */
46 private int mHeaderVersion;
47 private int mMagic;
48 private long mNanoAppId;
49 private int mNanoAppVersion;
50 private int mFlags;
51 private long mHwHubType;
52 private byte mTargetChreApiMajorVersion;
53 private byte mTargetChreApiMinorVersion;
54
55 private boolean mHasValidHeader = false;
56
57 /*
58 * The header version used to parse the binary in parseBinaryHeader().
59 */
60 private static final int EXPECTED_HEADER_VERSION = 1;
61
62 /*
Arthur Ishiguro0d719c22017-10-30 16:41:40 -070063 * The magic value expected in the header as defined in context_hub.h.
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070064 */
65 private static final int EXPECTED_MAGIC_VALUE =
66 (((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24));
67
68 /*
69 * Byte order established in context_hub.h
70 */
71 private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
72
Arthur Ishiguro0d719c22017-10-30 16:41:40 -070073 /*
74 * The size of the header in bytes as defined in context_hub.h.
75 */
76 private static final int HEADER_SIZE_BYTES = 40;
77
78 /*
79 * The bit fields for mFlags as defined in context_hub.h.
80 */
81 private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
82 private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
83
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -070084 public NanoAppBinary(byte[] appBinary) {
85 mNanoAppBinary = appBinary;
86 parseBinaryHeader();
87 }
88
89 /*
90 * Parses the binary header and populates its field using mNanoAppBinary.
91 */
92 private void parseBinaryHeader() {
93 ByteBuffer buf = ByteBuffer.wrap(mNanoAppBinary).order(HEADER_ORDER);
94
95 mHasValidHeader = false;
96 try {
97 mHeaderVersion = buf.getInt();
98 if (mHeaderVersion != EXPECTED_HEADER_VERSION) {
99 Log.e(TAG, "Unexpected header version " + mHeaderVersion + " while parsing header"
100 + " (expected " + EXPECTED_HEADER_VERSION + ")");
101 return;
102 }
103
104 mMagic = buf.getInt();
105 mNanoAppId = buf.getLong();
106 mNanoAppVersion = buf.getInt();
107 mFlags = buf.getInt();
108 mHwHubType = buf.getLong();
109 mTargetChreApiMajorVersion = buf.get();
110 mTargetChreApiMinorVersion = buf.get();
111 } catch (BufferUnderflowException e) {
112 Log.e(TAG, "Not enough contents in nanoapp header");
113 return;
114 }
115
116 if (mMagic != EXPECTED_MAGIC_VALUE) {
117 Log.e(TAG, "Unexpected magic value " + String.format("0x%08X", mMagic)
118 + "while parsing header (expected "
119 + String.format("0x%08X", EXPECTED_MAGIC_VALUE) + ")");
120 } else {
121 mHasValidHeader = true;
122 }
123 }
124
125 /**
126 * @return the app binary byte array
127 */
Arthur Ishiguro0d719c22017-10-30 16:41:40 -0700128 public byte[] getBinary() {
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700129 return mNanoAppBinary;
130 }
131
132 /**
Arthur Ishiguro0d719c22017-10-30 16:41:40 -0700133 * @return the app binary byte array without the leading header
134 *
135 * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
136 * @throws NullPointerException if the nanoapp binary is null
137 */
138 public byte[] getBinaryNoHeader() {
139 if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
140 throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
141 + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
142 }
143
144 return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
145 }
146
147 /**
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700148 * @return {@code true} if the header is valid, {@code false} otherwise
149 */
150 public boolean hasValidHeader() {
151 return mHasValidHeader;
152 }
153
154 /**
155 * @return the header version
156 */
157 public int getHeaderVersion() {
158 return mHeaderVersion;
159 }
160
161 /**
162 * @return the app ID parsed from the nanoapp header
163 */
164 public long getNanoAppId() {
165 return mNanoAppId;
166 }
167
168 /**
169 * @return the app version parsed from the nanoapp header
170 */
171 public int getNanoAppVersion() {
172 return mNanoAppVersion;
173 }
174
175 /**
176 * @return the compile target hub type parsed from the nanoapp header
177 */
178 public long getHwHubType() {
179 return mHwHubType;
180 }
181
182 /**
183 * @return the target CHRE API major version parsed from the nanoapp header
184 */
185 public byte getTargetChreApiMajorVersion() {
186 return mTargetChreApiMajorVersion;
187 }
188
189 /**
190 * @return the target CHRE API minor version parsed from the nanoapp header
191 */
192 public byte getTargetChreApiMinorVersion() {
193 return mTargetChreApiMinorVersion;
194 }
195
Arthur Ishiguro0d719c22017-10-30 16:41:40 -0700196 /**
197 * Returns the flags for the nanoapp as defined in context_hub.h.
198 *
199 * This method is meant to be used by the Context Hub Service.
200 *
201 * @return the flags for the nanoapp
202 */
203 public int getFlags() {
204 return mFlags;
205 }
206
207 /**
208 * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
209 */
210 public boolean isSigned() {
211 return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
212 }
213
214 /**
215 * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
216 */
217 public boolean isEncrypted() {
218 return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
219 }
220
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700221 private NanoAppBinary(Parcel in) {
222 int binaryLength = in.readInt();
223 mNanoAppBinary = new byte[binaryLength];
224 in.readByteArray(mNanoAppBinary);
225
226 parseBinaryHeader();
227 }
228
229 @Override
230 public int describeContents() {
231 return 0;
232 }
233
234 @Override
235 public void writeToParcel(Parcel out, int flags) {
236 out.writeInt(mNanoAppBinary.length);
237 out.writeByteArray(mNanoAppBinary);
238 }
239
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700240 public static final @android.annotation.NonNull Creator<NanoAppBinary> CREATOR =
Arthur Ishigurob9ae7bd2017-10-09 12:47:52 -0700241 new Creator<NanoAppBinary>() {
242 @Override
243 public NanoAppBinary createFromParcel(Parcel in) {
244 return new NanoAppBinary(in);
245 }
246
247 @Override
248 public NanoAppBinary[] newArray(int size) {
249 return new NanoAppBinary[size];
250 }
251 };
252}