Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e4adc9e1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I4395fb12,I89a77a30

* changes:
  Expose headerless binary and flags in NanoAppBinary
  Sets up ContextHub service/manager interface for transactions
parents e20e09d1 0d719c2a
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -218,6 +218,7 @@ LOCAL_SRC_FILES += \
	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
	core/java/android/hardware/location/IContextHubCallback.aidl \
	core/java/android/hardware/location/IContextHubService.aidl \
	core/java/android/hardware/location/IContextHubTransactionCallback.aidl \
	core/java/android/hardware/radio/IRadioService.aidl \
	core/java/android/hardware/radio/ITuner.aidl \
	core/java/android/hardware/radio/ITunerCallback.aidl \
+54 −1
Original line number Diff line number Diff line
@@ -271,6 +271,59 @@ public final class ContextHubManager {
        throw new UnsupportedOperationException("TODO: Implement this");
    }

    /*
     * Helper function to generate a stub for a non-query transaction callback.
     *
     * @param transaction the transaction to unblock when complete
     *
     * @return the callback
     *
     * @hide
     */
    private IContextHubTransactionCallback createTransactionCallback(
            ContextHubTransaction<Void> transaction) {
        return new IContextHubTransactionCallback.Stub() {
            @Override
            public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
                Log.e(TAG, "Received a query callback on a non-query request");
                transaction.setResponse(new ContextHubTransaction.Response<Void>(
                        ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
            }

            @Override
            public void onTransactionComplete(int result) {
                transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
            }
        };
    }

   /*
    * Helper function to generate a stub for a query transaction callback.
    *
    * @param transaction the transaction to unblock when complete
    *
    * @return the callback
    *
    * @hide
    */
    private IContextHubTransactionCallback createQueryCallback(
            ContextHubTransaction<List<NanoAppState>> transaction) {
        return new IContextHubTransactionCallback.Stub() {
            @Override
            public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
                transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
                        result, nanoappList));
            }

            @Override
            public void onTransactionComplete(int result) {
                Log.e(TAG, "Received a non-query callback on a query request");
                transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
                        ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
            }
        };
    }

    /**
     * Loads a nanoapp at the specified Context Hub.
     *
@@ -411,7 +464,7 @@ public final class ContextHubManager {
     *
     * @param callback the notification callback to register
     * @param hubInfo the hub to attach this client to
     * @param handler the handler to invoke the callback, if null uses the current thread Looper
     * @param handler the handler to invoke the callback, if null uses the main thread's Looper
     *
     * @return the registered client object
     *
+129 −23
Original line number Diff line number Diff line
@@ -16,11 +16,16 @@
package android.hardware.location;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * A class describing a request sent to the Context Hub Service.
@@ -29,17 +34,15 @@ import java.util.concurrent.TimeUnit;
 * through the ContextHubManager APIs. The caller can either retrieve the result
 * synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
 * asynchronously through a user-defined callback
 * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}).
 *
 * A transaction can be invalidated if the caller of the transaction is no longer active
 * and the reference to this object is lost, or if timeout period has passed in
 * {@link #waitForResponse(long, TimeUnit)}.
 * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}).
 *
 * @param <T> the type of the contents in the transaction response
 *
 * @hide
 */
public class ContextHubTransaction<T> {
    private static final String TAG = "ContextHubTransaction";

    /**
     * Constants describing the type of a transaction through the Context Hub Service.
     */
@@ -68,7 +71,8 @@ public class ContextHubTransaction<T> {
            TRANSACTION_FAILED_UNINITIALIZED,
            TRANSACTION_FAILED_PENDING,
            TRANSACTION_FAILED_AT_HUB,
            TRANSACTION_FAILED_TIMEOUT})
            TRANSACTION_FAILED_TIMEOUT,
            TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
    public @interface Result {}
    public static final int TRANSACTION_SUCCESS = 0;
    /**
@@ -95,6 +99,10 @@ public class ContextHubTransaction<T> {
     * Failure mode when the transaction has timed out.
     */
    public static final int TRANSACTION_FAILED_TIMEOUT = 6;
    /**
     * Failure mode when the transaction has failed internally at the service.
     */
    public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;

    /**
     * A class describing the response for a ContextHubTransaction.
@@ -145,11 +153,6 @@ public class ContextHubTransaction<T> {
                ContextHubTransaction<C> transaction, ContextHubTransaction.Response<C> response);
    }

    /*
     * The unique identifier representing the transaction.
     */
    private int mTransactionId;

    /*
     * The type of the transaction.
     */
@@ -171,8 +174,17 @@ public class ContextHubTransaction<T> {
     */
    private ContextHubTransaction.Callback<T> mCallback = null;

    ContextHubTransaction(int id, @Type int type) {
        mTransactionId = id;
    /*
     * Synchronization latch used to block on response.
     */
    private final CountDownLatch mDoneSignal = new CountDownLatch(1);

    /*
     * true if the response has been set throught setResponse, false otherwise.
     */
    private boolean mIsResponseSet = false;

    ContextHubTransaction(@Type int type) {
        mTransactionType = type;
    }

@@ -191,17 +203,26 @@ public class ContextHubTransaction<T> {
     * for the transaction represented by this object by the Context Hub, or a
     * specified timeout period has elapsed.
     *
     * If the specified timeout has passed, the transaction represented by this object
     * is invalidated by the Context Hub Service (resulting in a timeout failure in the
     * response).
     * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
     * retry the invocation of this method at a later time.
     *
     * @param timeout the timeout duration
     * @param unit the unit of the timeout
     *
     * @return the transaction response
     *
     * @throws InterruptedException if the current thread is interrupted while waiting for response
     * @throws TimeoutException if the timeout period has passed
     */
    public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) {
        throw new UnsupportedOperationException("TODO: Implement this");
    public ContextHubTransaction.Response<T> waitForResponse(
            long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
        boolean success = mDoneSignal.await(timeout, unit);

        if (!success) {
            throw new TimeoutException("Timed out while waiting for transaction");
        }

        return mResponse;
    }

    /**
@@ -215,15 +236,100 @@ public class ContextHubTransaction<T> {
     * will be immediately posted by the handler. If the transaction has been invalidated,
     * the callback will never be invoked.
     *
     * A transaction can be invalidated if the process owning the transaction is no longer active
     * and the reference to this object is lost.
     *
     * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be
     * invoked once, or an IllegalStateException will be thrown.
     *
     * @param callback the callback to be invoked upon completion
     * @param handler the handler to post the callback
     *
     * @throws IllegalStateException if this method is called multiple times
     * @throws NullPointerException if the callback or handler is null
     */
    public void setCallbackOnComplete(
            @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) {
        synchronized (this) {
            if (callback == null) {
                throw new NullPointerException("Callback cannot be null");
            }
            if (handler == null) {
                throw new NullPointerException("Handler cannot be null");
            }
            if (mCallback != null) {
                throw new IllegalStateException(
                        "Cannot set ContextHubTransaction callback multiple times");
            }

            mCallback = callback;
            mHandler = handler;

            if (mDoneSignal.getCount() == 0) {
                boolean callbackPosted = mHandler.post(() -> {
                    mCallback.onComplete(this, mResponse);
                });

                if (!callbackPosted) {
                    Log.e(TAG, "Failed to post callback to Handler");
                }
            }
        }
    }

    /**
     * Sets a callback to be invoked when the transaction completes.
     *
     * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
     * with the handler being that of the main thread's Looper.
     *
     * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
     * can only be invoked once, or an IllegalStateException will be thrown.
     *
     * @param callback the callback to be invoked upon completion
     *
     * @throws IllegalStateException if this method is called multiple times
     * @throws NullPointerException if the callback is null
     */
    public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) {
        throw new UnsupportedOperationException("TODO: Implement this");
    public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) {
        setCallbackOnComplete(callback, new Handler(Looper.getMainLooper()));
    }

    /**
     * Sets the response of the transaction.
     *
     * This method should only be invoked by ContextHubManager as a result of a callback from
     * the Context Hub Service indicating the response from a transaction. This method should not be
     * invoked more than once.
     *
     * @param response the response to set
     *
     * @throws IllegalStateException if this method is invoked multiple times
     * @throws NullPointerException if the response is null
     */
    void setResponse(ContextHubTransaction.Response<T> response) {
        synchronized (this) {
            if (response == null) {
                throw new NullPointerException("Response cannot be null");
            }
            if (mIsResponseSet) {
                throw new IllegalStateException(
                        "Cannot set response of ContextHubTransaction multiple times");
            }

    private void setResponse(ContextHubTransaction.Response<T> response) {
            mResponse = response;
        throw new UnsupportedOperationException("TODO: Unblock waitForResponse");
            mIsResponseSet = true;

            mDoneSignal.countDown();
            if (mCallback != null) {
                boolean callbackPosted = mHandler.post(() -> {
                    mCallback.onComplete(this, mResponse);
                });

                if (!callbackPosted) {
                    Log.e(TAG, "Failed to post callback to Handler");
                }
            }
        }
    }
}
+35 −0
Original line number Diff line number Diff line
/*
 * 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.hardware.location.NanoAppState;

/**
 * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a
 * transaction. The callbacks are unique for each type of transaction, and the service is
 * responsible for invoking the correct callback.
 *
 * @hide
 */
oneway interface IContextHubTransactionCallback {

    // Callback to be invoked when a query request completes
    void onQueryResponse(int result, in List<NanoAppState> nanoappList);

    // Callback to be invoked when a non-query request completes
    void onTransactionComplete(int result);
}
+54 −2
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.Log;
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;

/**
 * @hide
@@ -57,7 +58,7 @@ public final class NanoAppBinary implements Parcelable {
    private static final int EXPECTED_HEADER_VERSION = 1;

    /*
     * The magic value expected in the header.
     * 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));
@@ -67,6 +68,17 @@ public final class NanoAppBinary implements Parcelable {
     */
    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();
@@ -111,10 +123,25 @@ public final class NanoAppBinary implements Parcelable {
    /**
     * @return the app binary byte array
     */
    public byte[] getNanoAppBinary() {
    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
     */
@@ -164,6 +191,31 @@ public final class NanoAppBinary implements Parcelable {
        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];