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

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

Merge "Factor out service handling out of RuntimePermissionPresenter"

parents 1dd29096 22b84988
Loading
Loading
Loading
Loading
+168 −153
Original line number Original line Diff line number Diff line
@@ -16,27 +16,28 @@


package android.permission;
package android.permission;


import static android.permission.RuntimePermissionPresenterService.SERVICE_INTERFACE;

import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteCallback;
import android.os.RemoteCallback;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Log;
import android.util.Log;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.infra.AbstractMultiplePendingRequestsRemoteService;
import com.android.internal.infra.AbstractRemoteService;


import java.util.ArrayList;
import java.util.Collections;
import java.util.Collections;
import java.util.List;
import java.util.List;


@@ -80,7 +81,7 @@ public final class RuntimePermissionPresenter {
     */
     */
    public interface OnCountPermissionAppsResultCallback {
    public interface OnCountPermissionAppsResultCallback {
        /**
        /**
         * The result for {@link #countPermissionApps(List, boolean,
         * The result for {@link #countPermissionApps(List, boolean, boolean,
         * OnCountPermissionAppsResultCallback, Handler)}.
         * OnCountPermissionAppsResultCallback, Handler)}.
         *
         *
         * @param numApps The number of apps that have one of the permissions
         * @param numApps The number of apps that have one of the permissions
@@ -110,8 +111,13 @@ public final class RuntimePermissionPresenter {
        }
        }
    }
    }


    private RuntimePermissionPresenter(Context context) {
    private RuntimePermissionPresenter(@NonNull Context context) {
        mRemoteService = new RemoteService(context);
        Intent intent = new Intent(SERVICE_INTERFACE);
        intent.setPackage(context.getPackageManager().getPermissionControllerPackageName());
        ResolveInfo serviceInfo = context.getPackageManager().resolveService(intent, 0);

        mRemoteService = new RemoteService(context,
                serviceInfo.getComponentInfo().getComponentName());
    }
    }


    /**
    /**
@@ -126,8 +132,8 @@ public final class RuntimePermissionPresenter {
        checkNotNull(packageName);
        checkNotNull(packageName);
        checkNotNull(callback);
        checkNotNull(callback);


        mRemoteService.processMessage(obtainMessage(RemoteService::getAppPermissions,
        mRemoteService.scheduleRequest(new PendingGetAppPermissionRequest(mRemoteService,
                mRemoteService, packageName, callback, handler));
                packageName, callback, handler == null ? mRemoteService.getHandler() : handler));
    }
    }


    /**
    /**
@@ -141,8 +147,8 @@ public final class RuntimePermissionPresenter {
        checkNotNull(packageName);
        checkNotNull(packageName);
        checkNotNull(permissionName);
        checkNotNull(permissionName);


        mRemoteService.processMessage(obtainMessage(RemoteService::revokeAppPermissions,
        mRemoteService.scheduleAsyncRequest(new PendingRevokeAppPermissionRequest(packageName,
                mRemoteService, packageName, permissionName));
                permissionName));
    }
    }


    /**
    /**
@@ -160,76 +166,87 @@ public final class RuntimePermissionPresenter {
        checkCollectionElementsNotNull(permissionNames, "permissionNames");
        checkCollectionElementsNotNull(permissionNames, "permissionNames");
        checkNotNull(callback);
        checkNotNull(callback);


        mRemoteService.processMessage(obtainMessage(RemoteService::countPermissionApps,
        mRemoteService.scheduleRequest(new PendingCountPermissionAppsRequest(mRemoteService,
                mRemoteService, permissionNames, countOnlyGranted, countSystem, callback, handler));
                permissionNames, countOnlyGranted, countSystem, callback,
                handler == null ? mRemoteService.getHandler() : handler));
    }
    }


    private static final class RemoteService
    /**
            extends Handler implements ServiceConnection {
     * A connection to the remote service
     */
    static final class RemoteService extends
            AbstractMultiplePendingRequestsRemoteService<RemoteService,
                    IRuntimePermissionPresenter>  {
        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
        private static final long MESSAGE_TIMEOUT_MILLIS = 30000;


        public static final int MSG_UNBIND = 0;
        /**

         * Create a connection to the remote service
        private final Object mLock = new Object();
         *

         * @param context A context to use
        private final Context mContext;
         * @param componentName The component of the service to connect to

         */
        @GuardedBy("mLock")
        RemoteService(@NonNull Context context, @NonNull ComponentName componentName) {
        private final List<Message> mPendingWork = new ArrayList<>();
            super(context, SERVICE_INTERFACE, componentName, UserHandle.myUserId(),

                    service -> Log.e(TAG, "RuntimePermPresenterService " + service + " died"),
        @GuardedBy("mLock")
                    false, false, 1);
        private IRuntimePermissionPresenter mRemoteInstance;

        @GuardedBy("mLock")
        private boolean mBound;

        RemoteService(Context context) {
            super(context.getMainLooper(), null, false);
            mContext = context;
        }
        }


        public void processMessage(Message message) {
        /**
            synchronized (mLock) {
         * @return The default handler used by this service.
                if (!mBound) {
         */
                    Intent intent = new Intent(
        Handler getHandler() {
                            RuntimePermissionPresenterService.SERVICE_INTERFACE);
            return mHandler;
                    intent.setPackage(mContext.getPackageManager()
                            .getPermissionControllerPackageName());
                    mBound = mContext.bindService(intent, this,
                            Context.BIND_AUTO_CREATE);
                }
                mPendingWork.add(message);
                scheduleNextMessageIfNeededLocked();
            }
        }
        }


        @Override
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
        protected @NonNull IRuntimePermissionPresenter getServiceInterface(
            synchronized (mLock) {
                @NonNull IBinder binder) {
                mRemoteInstance = IRuntimePermissionPresenter.Stub.asInterface(service);
            return IRuntimePermissionPresenter.Stub.asInterface(binder);
                scheduleNextMessageIfNeededLocked();
        }
        }

        @Override
        protected long getTimeoutIdleBindMillis() {
            return UNBIND_TIMEOUT_MILLIS;
        }
        }


        @Override
        @Override
        public void onServiceDisconnected(ComponentName name) {
        protected long getRemoteRequestMillis() {
            synchronized (mLock) {
            return MESSAGE_TIMEOUT_MILLIS;
                mRemoteInstance = null;
        }
        }

        @Override
        public void scheduleRequest(@NonNull PendingRequest<RemoteService,
                IRuntimePermissionPresenter> pendingRequest) {
            super.scheduleRequest(pendingRequest);
        }
        }


        private void getAppPermissions(@NonNull String packageName,
        @Override
                @NonNull OnGetAppPermissionResultCallback callback, @Nullable Handler handler) {
        public void scheduleAsyncRequest(
            final IRuntimePermissionPresenter remoteInstance;
                @NonNull AsyncRequest<IRuntimePermissionPresenter> request) {
            synchronized (mLock) {
            super.scheduleAsyncRequest(request);
                remoteInstance = mRemoteInstance;
        }
        }
            if (remoteInstance == null) {
                return;
    }
    }
            try {

                remoteInstance.getAppPermissions(packageName,
    /**
                        new RemoteCallback(result -> {
     * Request for {@link #getAppPermissions}
     */
    private static final class PendingGetAppPermissionRequest extends
            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
        private final @NonNull String mPackageName;
        private final @NonNull OnGetAppPermissionResultCallback mCallback;

        private final @NonNull RemoteCallback mRemoteCallback;

        private PendingGetAppPermissionRequest(@NonNull RemoteService service,
                @NonNull String packageName, @NonNull OnGetAppPermissionResultCallback callback,
                @NonNull Handler handler) {
            super(service);

            mPackageName = packageName;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> {
                final List<RuntimePermissionPresentationInfo> reportedPermissions;
                final List<RuntimePermissionPresentationInfo> reportedPermissions;
                List<RuntimePermissionPresentationInfo> permissions = null;
                List<RuntimePermissionPresentationInfo> permissions = null;
                if (result != null) {
                if (result != null) {
@@ -239,58 +256,76 @@ public final class RuntimePermissionPresenter {
                    permissions = Collections.emptyList();
                    permissions = Collections.emptyList();
                }
                }
                reportedPermissions = permissions;
                reportedPermissions = permissions;
                            if (handler != null) {

                                handler.post(
                                        () -> callback.onGetAppPermissions(reportedPermissions));
                            } else {
                callback.onGetAppPermissions(reportedPermissions);
                callback.onGetAppPermissions(reportedPermissions);
                            }
                        }, this));
            } catch (RemoteException re) {
                Log.e(TAG, "Error getting app permissions", re);
            }
            scheduleUnbind();


            synchronized (mLock) {
                finish();
                scheduleNextMessageIfNeededLocked();
            }, handler);
            }
        }
        }


        private void revokeAppPermissions(@NonNull String packageName,
        @Override
                @NonNull String permissionName) {
        protected void onTimeout(RemoteService remoteService) {
            final IRuntimePermissionPresenter remoteInstance;
            mCallback.onGetAppPermissions(Collections.emptyList());
            synchronized (mLock) {
                remoteInstance = mRemoteInstance;
            }
            if (remoteInstance == null) {
                return;
        }
        }

        @Override
        public void run() {
            try {
            try {
                remoteInstance.revokeRuntimePermission(packageName, permissionName);
                getService().getServiceInterface().getAppPermissions(mPackageName, mRemoteCallback);
            } catch (RemoteException re) {
            } catch (RemoteException e) {
                Log.e(TAG, "Error getting app permissions", re);
                Log.e(TAG, "Error getting app permission", e);
            }
            }

            synchronized (mLock) {
                scheduleNextMessageIfNeededLocked();
        }
        }
    }
    }


        private void countPermissionApps(@NonNull List<String> permissionNames,
    /**
                boolean countOnlyGranted, boolean countSystem,
     * Request for {@link #revokeRuntimePermission}
                @NonNull OnCountPermissionAppsResultCallback callback, @Nullable Handler handler) {
     */
            final IRuntimePermissionPresenter remoteInstance;
    private static final class PendingRevokeAppPermissionRequest
            implements AbstractRemoteService.AsyncRequest<IRuntimePermissionPresenter> {
        private final @NonNull String mPackageName;
        private final @NonNull String mPermissionName;


            synchronized (mLock) {
        private PendingRevokeAppPermissionRequest(@NonNull String packageName,
                remoteInstance = mRemoteInstance;
                @NonNull String permissionName) {
            }
            mPackageName = packageName;
            if (remoteInstance == null) {
            mPermissionName = permissionName;
                return;
        }
        }


        @Override
        public void run(IRuntimePermissionPresenter remoteInterface) {
            try {
            try {
                remoteInstance.countPermissionApps(permissionNames, countOnlyGranted, countSystem,
                remoteInterface.revokeRuntimePermission(mPackageName, mPermissionName);
                        new RemoteCallback(result -> {
            } catch (RemoteException e) {
                Log.e(TAG, "Error revoking app permission", e);
            }
        }
    }

    /**
     * Request for {@link #countPermissionApps}
     */
    private static final class PendingCountPermissionAppsRequest extends
            AbstractRemoteService.PendingRequest<RemoteService, IRuntimePermissionPresenter> {
        private final @NonNull List<String> mPermissionNames;
        private final @NonNull OnCountPermissionAppsResultCallback mCallback;
        private final boolean mCountOnlyGranted;
        private final boolean mCountSystem;

        private final @NonNull RemoteCallback mRemoteCallback;

        private PendingCountPermissionAppsRequest(@NonNull RemoteService service,
                @NonNull List<String> permissionNames, boolean countOnlyGranted,
                boolean countSystem, @NonNull OnCountPermissionAppsResultCallback callback,
                @NonNull Handler handler) {
            super(service);

            mPermissionNames = permissionNames;
            mCountOnlyGranted = countOnlyGranted;
            mCountSystem = countSystem;
            mCallback = callback;

            mRemoteCallback = new RemoteCallback(result -> {
                final int numApps;
                final int numApps;
                if (result != null) {
                if (result != null) {
                    numApps = result.getInt(KEY_RESULT);
                    numApps = result.getInt(KEY_RESULT);
@@ -298,45 +333,25 @@ public final class RuntimePermissionPresenter {
                    numApps = 0;
                    numApps = 0;
                }
                }


                            if (handler != null) {
                                handler.post(() -> callback.onCountPermissionApps(numApps));
                            } else {
                callback.onCountPermissionApps(numApps);
                callback.onCountPermissionApps(numApps);
                            }
                        }, this));
            } catch (RemoteException re) {
                Log.e(TAG, "Error counting permission apps", re);
            }

            scheduleUnbind();


            synchronized (mLock) {
                finish();
                scheduleNextMessageIfNeededLocked();
            }, handler);
            }
        }
        }


        private void unbind() {
        @Override
            synchronized (mLock) {
        protected void onTimeout(RemoteService remoteService) {
                if (mBound) {
            mCallback.onCountPermissionApps(0);
                    mContext.unbindService(this);
                    mBound = false;
                }
                mRemoteInstance = null;
            }
        }
        }


        @GuardedBy("mLock")
        @Override
        private void scheduleNextMessageIfNeededLocked() {
        public void run() {
            if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
            try {
                Message nextMessage = mPendingWork.remove(0);
                getService().getServiceInterface().countPermissionApps(mPermissionNames,
                sendMessage(nextMessage);
                        mCountOnlyGranted, mCountSystem, mRemoteCallback);
            }
            } catch (RemoteException e) {
                Log.e(TAG, "Error counting permission apps", e);
            }
            }

        private void scheduleUnbind() {
            removeMessages(MSG_UNBIND);
            sendMessageDelayed(PooledLambda.obtainMessage(RemoteService::unbind, this)
                    .setWhat(MSG_UNBIND), UNBIND_TIMEOUT_MILLIS);
        }
        }
    }
    }
}
}
+10 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.internal.infra;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.Context;
import android.content.Context;
import android.content.Intent;
import android.content.Intent;
@@ -164,6 +165,15 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
     */
     */
    protected abstract long getRemoteRequestMillis();
    protected abstract long getRemoteRequestMillis();


    /**
     * Gets the currently registered service interface or {@code null} if the service is not
     * connected.
     */
    @Nullable
    public final I getServiceInterface() {
        return mService;
    }

    private void handleDestroy() {
    private void handleDestroy() {
        if (checkIfDestroyed()) return;
        if (checkIfDestroyed()) return;
        handleOnDestroy();
        handleOnDestroy();