253 lines
7.2 KiB
Java
253 lines
7.2 KiB
Java
/*
|
|
* Copyright 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
package android.hardware.location;
|
|
|
|
import android.annotation.SystemApi;
|
|
import android.os.Parcel;
|
|
import android.os.Parcelable;
|
|
import android.util.Log;
|
|
|
|
import java.nio.BufferUnderflowException;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.util.Arrays;
|
|
|
|
/**
|
|
* @hide
|
|
*/
|
|
@SystemApi
|
|
public final class NanoAppBinary implements Parcelable {
|
|
private static final String TAG = "NanoAppBinary";
|
|
|
|
/*
|
|
* The contents of the app binary.
|
|
*/
|
|
private byte[] mNanoAppBinary;
|
|
|
|
/*
|
|
* Contents of the nanoapp binary header.
|
|
*
|
|
* Only valid if mHasValidHeader is true.
|
|
* See nano_app_binary_t in context_hub.h for details.
|
|
*/
|
|
private int mHeaderVersion;
|
|
private int mMagic;
|
|
private long mNanoAppId;
|
|
private int mNanoAppVersion;
|
|
private int mFlags;
|
|
private long mHwHubType;
|
|
private byte mTargetChreApiMajorVersion;
|
|
private byte mTargetChreApiMinorVersion;
|
|
|
|
private boolean mHasValidHeader = false;
|
|
|
|
/*
|
|
* The header version used to parse the binary in parseBinaryHeader().
|
|
*/
|
|
private static final int EXPECTED_HEADER_VERSION = 1;
|
|
|
|
/*
|
|
* The magic value expected in the header as defined in context_hub.h.
|
|
*/
|
|
private static final int EXPECTED_MAGIC_VALUE =
|
|
(((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24));
|
|
|
|
/*
|
|
* Byte order established in context_hub.h
|
|
*/
|
|
private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
|
|
|
|
/*
|
|
* The size of the header in bytes as defined in context_hub.h.
|
|
*/
|
|
private static final int HEADER_SIZE_BYTES = 40;
|
|
|
|
/*
|
|
* The bit fields for mFlags as defined in context_hub.h.
|
|
*/
|
|
private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
|
|
private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
|
|
|
|
public NanoAppBinary(byte[] appBinary) {
|
|
mNanoAppBinary = appBinary;
|
|
parseBinaryHeader();
|
|
}
|
|
|
|
/*
|
|
* Parses the binary header and populates its field using mNanoAppBinary.
|
|
*/
|
|
private void parseBinaryHeader() {
|
|
ByteBuffer buf = ByteBuffer.wrap(mNanoAppBinary).order(HEADER_ORDER);
|
|
|
|
mHasValidHeader = false;
|
|
try {
|
|
mHeaderVersion = buf.getInt();
|
|
if (mHeaderVersion != EXPECTED_HEADER_VERSION) {
|
|
Log.e(TAG, "Unexpected header version " + mHeaderVersion + " while parsing header"
|
|
+ " (expected " + EXPECTED_HEADER_VERSION + ")");
|
|
return;
|
|
}
|
|
|
|
mMagic = buf.getInt();
|
|
mNanoAppId = buf.getLong();
|
|
mNanoAppVersion = buf.getInt();
|
|
mFlags = buf.getInt();
|
|
mHwHubType = buf.getLong();
|
|
mTargetChreApiMajorVersion = buf.get();
|
|
mTargetChreApiMinorVersion = buf.get();
|
|
} catch (BufferUnderflowException e) {
|
|
Log.e(TAG, "Not enough contents in nanoapp header");
|
|
return;
|
|
}
|
|
|
|
if (mMagic != EXPECTED_MAGIC_VALUE) {
|
|
Log.e(TAG, "Unexpected magic value " + String.format("0x%08X", mMagic)
|
|
+ "while parsing header (expected "
|
|
+ String.format("0x%08X", EXPECTED_MAGIC_VALUE) + ")");
|
|
} else {
|
|
mHasValidHeader = true;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return the app binary byte array
|
|
*/
|
|
public byte[] getBinary() {
|
|
return mNanoAppBinary;
|
|
}
|
|
|
|
/**
|
|
* @return the app binary byte array without the leading header
|
|
*
|
|
* @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
|
|
* @throws NullPointerException if the nanoapp binary is null
|
|
*/
|
|
public byte[] getBinaryNoHeader() {
|
|
if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
|
|
throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
|
|
+ mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
|
|
}
|
|
|
|
return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the header is valid, {@code false} otherwise
|
|
*/
|
|
public boolean hasValidHeader() {
|
|
return mHasValidHeader;
|
|
}
|
|
|
|
/**
|
|
* @return the header version
|
|
*/
|
|
public int getHeaderVersion() {
|
|
return mHeaderVersion;
|
|
}
|
|
|
|
/**
|
|
* @return the app ID parsed from the nanoapp header
|
|
*/
|
|
public long getNanoAppId() {
|
|
return mNanoAppId;
|
|
}
|
|
|
|
/**
|
|
* @return the app version parsed from the nanoapp header
|
|
*/
|
|
public int getNanoAppVersion() {
|
|
return mNanoAppVersion;
|
|
}
|
|
|
|
/**
|
|
* @return the compile target hub type parsed from the nanoapp header
|
|
*/
|
|
public long getHwHubType() {
|
|
return mHwHubType;
|
|
}
|
|
|
|
/**
|
|
* @return the target CHRE API major version parsed from the nanoapp header
|
|
*/
|
|
public byte getTargetChreApiMajorVersion() {
|
|
return mTargetChreApiMajorVersion;
|
|
}
|
|
|
|
/**
|
|
* @return the target CHRE API minor version parsed from the nanoapp header
|
|
*/
|
|
public byte getTargetChreApiMinorVersion() {
|
|
return mTargetChreApiMinorVersion;
|
|
}
|
|
|
|
/**
|
|
* Returns the flags for the nanoapp as defined in context_hub.h.
|
|
*
|
|
* This method is meant to be used by the Context Hub Service.
|
|
*
|
|
* @return the flags for the nanoapp
|
|
*/
|
|
public int getFlags() {
|
|
return mFlags;
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
|
|
*/
|
|
public boolean isSigned() {
|
|
return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
|
|
*/
|
|
public boolean isEncrypted() {
|
|
return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
|
|
}
|
|
|
|
private NanoAppBinary(Parcel in) {
|
|
int binaryLength = in.readInt();
|
|
mNanoAppBinary = new byte[binaryLength];
|
|
in.readByteArray(mNanoAppBinary);
|
|
|
|
parseBinaryHeader();
|
|
}
|
|
|
|
@Override
|
|
public int describeContents() {
|
|
return 0;
|
|
}
|
|
|
|
@Override
|
|
public void writeToParcel(Parcel out, int flags) {
|
|
out.writeInt(mNanoAppBinary.length);
|
|
out.writeByteArray(mNanoAppBinary);
|
|
}
|
|
|
|
public static final @android.annotation.NonNull Creator<NanoAppBinary> CREATOR =
|
|
new Creator<NanoAppBinary>() {
|
|
@Override
|
|
public NanoAppBinary createFromParcel(Parcel in) {
|
|
return new NanoAppBinary(in);
|
|
}
|
|
|
|
@Override
|
|
public NanoAppBinary[] newArray(int size) {
|
|
return new NanoAppBinary[size];
|
|
}
|
|
};
|
|
}
|