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

Commit bcd37b9c authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by Android (Google) Code Review
Browse files

Merge changes from topic "RecognitionServiceFeatureId"

* changes:
  Pipe through featureId from caller to noteOps in RecognitionService
  Add featureId to PermissionChecker
parents 139ab60d 83ae4822
Loading
Loading
Loading
Loading
+21 −16
Original line number Diff line number Diff line
@@ -114,6 +114,7 @@ public final class PermissionChecker {
     * @param uid The uid for which to check.
     * @param packageName The package name for which to check. If null the
     *     the first package for the calling UID will be used.
     * @param featureId Feature in the package
     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
     * @param message A message describing the reason the permission was checked
@@ -123,8 +124,8 @@ public final class PermissionChecker {
    @PermissionResult
    public static int checkPermissionForDataDelivery(@NonNull Context context,
            @NonNull String permission, int pid, int uid, @Nullable String packageName,
            @Nullable String message) {
        return checkPermissionCommon(context, permission, pid, uid, packageName, message,
            @Nullable String featureId, @Nullable String message) {
        return checkPermissionCommon(context, permission, pid, uid, packageName, featureId, message,
                true /*forDataDelivery*/);
    }

@@ -161,8 +162,8 @@ public final class PermissionChecker {
    @PermissionResult
    public static int checkPermissionForPreflight(@NonNull Context context,
            @NonNull String permission, int pid, int uid, @Nullable String packageName) {
        return checkPermissionCommon(context, permission, pid, uid, packageName, null /*message*/,
                false /*forDataDelivery*/);
        return checkPermissionCommon(context, permission, pid, uid, packageName, null /*featureId*/,
                null /*message*/, false /*forDataDelivery*/);
    }

    /**
@@ -197,7 +198,7 @@ public final class PermissionChecker {
    public static int checkSelfPermissionForDataDelivery(@NonNull Context context,
            @NonNull String permission, @Nullable String message) {
        return checkPermissionForDataDelivery(context, permission, Process.myPid(),
                Process.myUid(), context.getPackageName(), message);
                Process.myUid(), context.getPackageName(), context.getFeatureId(), message);
    }

    /**
@@ -256,6 +257,7 @@ public final class PermissionChecker {
     * @param permission The permission to check.
     * @param packageName The package name making the IPC. If null the
     *     the first package for the calling UID will be used.
     * @param featureId The feature inside of the app
     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
     * @param message A message describing the reason the permission was checked
@@ -264,12 +266,13 @@ public final class PermissionChecker {
     */
    @PermissionResult
    public static int checkCallingPermissionForDataDelivery(@NonNull Context context,
            @NonNull String permission, @Nullable String packageName, @Nullable String message) {
            @NonNull String permission, @Nullable String packageName,
            @Nullable String featureId, @Nullable String message) {
        if (Binder.getCallingPid() == Process.myPid()) {
            return PERMISSION_DENIED;
        }
        return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
                Binder.getCallingUid(), packageName, message);
                Binder.getCallingUid(), packageName, featureId, message);
    }

    /**
@@ -331,17 +334,20 @@ public final class PermissionChecker {
     * @param permission The permission to check.
     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
     * @param featureId feature Id of caller (if not self)
     * @param message A message describing the reason the permission was checked
     *
     * @see #checkCallingOrSelfPermissionForPreflight(Context, String)
     */
    @PermissionResult
    public static int checkCallingOrSelfPermissionForDataDelivery(@NonNull Context context,
            @NonNull String permission, @Nullable String message) {
            @NonNull String permission, @Nullable String featureId, @Nullable String message) {
        String packageName = (Binder.getCallingPid() == Process.myPid())
                ? context.getPackageName() : null;
        featureId = (Binder.getCallingPid() == Process.myPid())
                ? context.getFeatureId() : featureId;
        return checkPermissionForDataDelivery(context, permission, Binder.getCallingPid(),
                Binder.getCallingUid(), packageName, message);
                Binder.getCallingUid(), packageName, featureId, message);
    }

    /**
@@ -360,15 +366,15 @@ public final class PermissionChecker {
     * app's fg/gb state) and this check will not leave a trace that permission protected
     * data was delivered. When you are about to deliver the location data to a registered
     * listener you should use {@link #checkCallingOrSelfPermissionForDataDelivery(Context,
     * String, String)} which will evaluate the permission access based on the current fg/bg state
     * of the app and leave a record that the data was accessed.
     * String, String, String)} which will evaluate the permission access based on the current
     * fg/bg state of the app and leave a record that the data was accessed.
     *
     * @param context Context for accessing resources.
     * @param permission The permission to check.
     * @return The permission check result which is either {@link #PERMISSION_GRANTED}
     *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
     *
     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String)
     * @see #checkCallingOrSelfPermissionForDataDelivery(Context, String, String, String)
     */
    @PermissionResult
    public static int checkCallingOrSelfPermissionForPreflight(@NonNull Context context,
@@ -380,8 +386,8 @@ public final class PermissionChecker {
    }

    private static int checkPermissionCommon(@NonNull Context context, @NonNull String permission,
            int pid, int uid, @Nullable String packageName, @Nullable String message,
            boolean forDataDelivery) {
            int pid, int uid, @Nullable String packageName, @Nullable String featureId,
            @Nullable String message, boolean forDataDelivery) {
        if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
            return PERMISSION_DENIED;
        }
@@ -401,8 +407,7 @@ public final class PermissionChecker {
        }

        if (forDataDelivery) {
            // TODO moltmann: Set correct feature id
            if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, null, message)
            if (appOpsManager.noteProxyOpNoThrow(op, packageName, uid, featureId, message)
                    != AppOpsManager.MODE_ALLOWED) {
                return PERMISSION_DENIED_APP_OP;
            }
+10 −3
Original line number Diff line number Diff line
@@ -39,8 +39,11 @@ oneway interface IRecognitionService {
     *        this intent can contain extra parameters to manipulate the behavior of the recognition
     *        client. For more information see {@link RecognizerIntent}.
     * @param listener to receive callbacks, note that this must be non-null
     * @param packageName the package name calling this API
     * @param featureId The feature in the package
     */
    void startListening(in Intent recognizerIntent, in IRecognitionListener listener);
    void startListening(in Intent recognizerIntent, in IRecognitionListener listener,
            String packageName, String featureId);

    /**
     * Stops listening for speech. Speech captured so far will be recognized as
@@ -48,13 +51,17 @@ oneway interface IRecognitionService {
     * is called during the speech capturing.
     *
     * @param listener to receive callbacks, note that this must be non-null
     * @param packageName the package name calling this API
     * @param featureId The feature in the package
     */
    void stopListening(in IRecognitionListener listener);
    void stopListening(in IRecognitionListener listener, String packageName, String featureId);

    /**
     * Cancels the speech recognition.
     *
     * @param listener to receive callbacks, note that this must be non-null
     * @param packageName the package name calling this API
     * @param featureId The feature in the package
     */
    void cancel(in IRecognitionListener listener);
    void cancel(in IRecognitionListener listener, String packageName, String featureId);
}
+29 −9
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package android.speech;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.app.Service;
@@ -29,6 +31,8 @@ import android.os.Message;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.util.Preconditions;

import java.lang.ref.WeakReference;

/**
@@ -171,13 +175,17 @@ public abstract class RecognitionService extends Service {
     * 
     * @param listener to send the error message to in case of error
     * @param forDataDelivery If the permission check is for delivering the sensitive data.
     * @param packageName the package name of the caller
     * @param featureId The feature in the package
     * @return {@code true} if the caller has enough permissions, {@code false} otherwise
     */
    private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery) {
    private boolean checkPermissions(IRecognitionListener listener, boolean forDataDelivery,
            @NonNull String packageName, @Nullable String featureId) {
        if (DBG) Log.d(TAG, "checkPermissions");
        if (forDataDelivery) {
            if (PermissionChecker.checkCallingOrSelfPermissionForDataDelivery(this,
                    android.Manifest.permission.RECORD_AUDIO, null /*message*/)
            if (PermissionChecker.checkCallingPermissionForDataDelivery(this,
                    android.Manifest.permission.RECORD_AUDIO, packageName, featureId,
                    null /*message*/)
                             == PermissionChecker.PERMISSION_GRANTED) {
                return true;
            }
@@ -349,10 +357,14 @@ public abstract class RecognitionService extends Service {
        }

        @Override
        public void startListening(Intent recognizerIntent, IRecognitionListener listener) {
        public void startListening(Intent recognizerIntent, IRecognitionListener listener,
                String packageName, String featureId) {
            Preconditions.checkNotNull(packageName);

            if (DBG) Log.d(TAG, "startListening called by:" + listener.asBinder());
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener, true /*forDataDelivery*/)) {
            if (service != null && service.checkPermissions(listener, true /*forDataDelivery*/,
                    packageName, featureId)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_START_LISTENING, service.new StartListeningArgs(
                                recognizerIntent, listener, Binder.getCallingUid())));
@@ -360,20 +372,28 @@ public abstract class RecognitionService extends Service {
        }

        @Override
        public void stopListening(IRecognitionListener listener) {
        public void stopListening(IRecognitionListener listener, String packageName,
                String featureId) {
            Preconditions.checkNotNull(packageName);

            if (DBG) Log.d(TAG, "stopListening called by:" + listener.asBinder());
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) {
            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/,
                    packageName, featureId)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_STOP_LISTENING, listener));
            }
        }

        @Override
        public void cancel(IRecognitionListener listener) {
        public void cancel(IRecognitionListener listener, String packageName,
                String featureId) {
            Preconditions.checkNotNull(packageName);

            if (DBG) Log.d(TAG, "cancel called by:" + listener.asBinder());
            final RecognitionService service = mServiceRef.get();
            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/)) {
            if (service != null && service.checkPermissions(listener, false /*forDataDelivery*/,
                    packageName, featureId)) {
                service.mHandler.sendMessage(Message.obtain(service.mHandler,
                        MSG_CANCEL, listener));
            }
+6 −4
Original line number Diff line number Diff line
@@ -341,7 +341,8 @@ public class SpeechRecognizer {
            return;
        }
        try {
            mService.startListening(recognizerIntent, mListener);
            mService.startListening(recognizerIntent, mListener, mContext.getOpPackageName(),
                    mContext.getFeatureId());
            if (DBG) Log.d(TAG, "service start listening command succeded");
        } catch (final RemoteException e) {
            Log.e(TAG, "startListening() failed", e);
@@ -355,7 +356,8 @@ public class SpeechRecognizer {
            return;
        }
        try {
            mService.stopListening(mListener);
            mService.stopListening(mListener, mContext.getOpPackageName(),
                    mContext.getFeatureId());
            if (DBG) Log.d(TAG, "service stop listening command succeded");
        } catch (final RemoteException e) {
            Log.e(TAG, "stopListening() failed", e);
@@ -369,7 +371,7 @@ public class SpeechRecognizer {
            return;
        }
        try {
            mService.cancel(mListener);
            mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
            if (DBG) Log.d(TAG, "service cancel command succeded");
        } catch (final RemoteException e) {
            Log.e(TAG, "cancel() failed", e);
@@ -398,7 +400,7 @@ public class SpeechRecognizer {
    public void destroy() {
        if (mService != null) {
            try {
                mService.cancel(mListener);
                mService.cancel(mListener, mContext.getOpPackageName(), mContext.getFeatureId());
            } catch (final RemoteException e) {
                // Not important
            }