Home | History | Annotate | Download | only in location
      1 /*
      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  */
     16 package android.hardware.location;
     17 
     18 import android.annotation.SystemApi;
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.util.Log;
     22 
     23 import java.nio.BufferUnderflowException;
     24 import java.nio.ByteBuffer;
     25 import java.nio.ByteOrder;
     26 import java.util.Arrays;
     27 
     28 /**
     29  * @hide
     30  */
     31 @SystemApi
     32 public 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     /*
     63      * The magic value expected in the header as defined in context_hub.h.
     64      */
     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 
     73     /*
     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 
     84     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      */
    128     public byte[] getBinary() {
    129         return mNanoAppBinary;
    130     }
    131 
    132     /**
    133      * @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     /**
    148      * @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 
    196     /**
    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 
    221     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 
    240     public static final Creator<NanoAppBinary> CREATOR =
    241             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 }
    253