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

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

Merge changes from topic "update_mapping"

* changes:
  Rework how pinning works
  Follow prebuilt/API update
parents d7b6a384 38df280a
Loading
Loading
Loading
Loading
+2 −6
Original line number Diff line number Diff line
@@ -16,17 +16,13 @@

package android.app.slice;

import android.app.slice.ISliceListener;
import android.app.slice.SliceSpec;
import android.net.Uri;

/** @hide */
interface ISliceManager {
    void addSliceListener(in Uri uri, String pkg, in ISliceListener listener,
            in SliceSpec[] specs);
    void removeSliceListener(in Uri uri, String pkg, in ISliceListener listener);
    void pinSlice(String pkg, in Uri uri, in SliceSpec[] specs);
    void unpinSlice(String pkg, in Uri uri);
    void pinSlice(String pkg, in Uri uri, in SliceSpec[] specs, in IBinder token);
    void unpinSlice(String pkg, in Uri uri, in IBinder token);
    boolean hasSliceAccess(String pkg);
    SliceSpec[] getPinnedSpecs(in Uri uri, String pkg);
    int checkSlicePermission(in Uri uri, String pkg, int pid, int uid);
+6 −36
Original line number Diff line number Diff line
@@ -26,8 +26,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
@@ -73,6 +75,7 @@ public class SliceManager {
    private final Context mContext;
    private final ArrayMap<Pair<Uri, SliceCallback>, ISliceListener> mListenerLookup =
            new ArrayMap<>();
    private final IBinder mToken = new Binder();

    /**
     * Permission denied.
@@ -105,7 +108,6 @@ public class SliceManager {
    @Deprecated
    public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
            @NonNull List<SliceSpec> specs) {
        registerSliceCallback(uri, specs, mContext.getMainExecutor(), callback);
    }

    /**
@@ -114,7 +116,6 @@ public class SliceManager {
    @Deprecated
    public void registerSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback,
            @NonNull List<SliceSpec> specs, Executor executor) {
        registerSliceCallback(uri, specs, executor, callback);
    }

    /**
@@ -132,7 +133,6 @@ public class SliceManager {
     */
    public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
            @NonNull SliceCallback callback) {
        registerSliceCallback(uri, specs, mContext.getMainExecutor(), callback);
    }

    /**
@@ -150,32 +150,7 @@ public class SliceManager {
     */
    public void registerSliceCallback(@NonNull Uri uri, @NonNull List<SliceSpec> specs,
            @NonNull @CallbackExecutor Executor executor, @NonNull SliceCallback callback) {
        try {
            mService.addSliceListener(uri, mContext.getPackageName(),
                    getListener(uri, callback, new ISliceListener.Stub() {
                        @Override
                        public void onSliceUpdated(Slice s) throws RemoteException {
                            executor.execute(() -> callback.onSliceUpdated(s));
                        }
                    }), specs.toArray(new SliceSpec[specs.size()]));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    private ISliceListener getListener(Uri uri, SliceCallback callback,
            ISliceListener listener) {
        Pair<Uri, SliceCallback> key = new Pair<>(uri, callback);
        if (mListenerLookup.containsKey(key)) {
            try {
                mService.removeSliceListener(uri, mContext.getPackageName(),
                        mListenerLookup.get(key));
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        mListenerLookup.put(key, listener);
        return listener;
    }

    /**
@@ -189,12 +164,7 @@ public class SliceManager {
     * @see #registerSliceCallback
     */
    public void unregisterSliceCallback(@NonNull Uri uri, @NonNull SliceCallback callback) {
        try {
            mService.removeSliceListener(uri, mContext.getPackageName(),
                    mListenerLookup.remove(new Pair<>(uri, callback)));
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

    }

    /**
@@ -215,7 +185,7 @@ public class SliceManager {
    public void pinSlice(@NonNull Uri uri, @NonNull List<SliceSpec> specs) {
        try {
            mService.pinSlice(mContext.getPackageName(), uri,
                    specs.toArray(new SliceSpec[specs.size()]));
                    specs.toArray(new SliceSpec[specs.size()]), mToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
@@ -237,7 +207,7 @@ public class SliceManager {
     */
    public void unpinSlice(@NonNull Uri uri) {
        try {
            mService.unpinSlice(mContext.getPackageName(), uri);
            mService.unpinSlice(mContext.getPackageName(), uri, mToken);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+2 −2
Original line number Diff line number Diff line
@@ -160,8 +160,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe
            mRow.addView(button);

            PendingIntent pendingIntent = null;
            if (rc.getContentIntent() != null) {
                pendingIntent = rc.getContentIntent().getAction();
            if (rc.getPrimaryAction() != null) {
                pendingIntent = rc.getPrimaryAction().getAction();
            }
            mClickActions.put(button, pendingIntent);

+11 −119
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@ package com.android.server.slice;

import static android.app.slice.SliceManager.PERMISSION_GRANTED;

import android.app.slice.ISliceListener;
import android.app.slice.Slice;
import android.app.slice.SliceProvider;
import android.app.slice.SliceSpec;
@@ -106,10 +105,6 @@ public class PinnedSliceState {
        setSlicePinned(false);
    }

    public void onChange() {
        mService.getHandler().post(this::handleBind);
    }

    private void setSlicePinned(boolean pinned) {
        synchronized (mLock) {
            if (mSlicePinned == pinned) return;
@@ -122,45 +117,23 @@ public class PinnedSliceState {
        }
    }

    public void addSliceListener(ISliceListener listener, String pkg, SliceSpec[] specs,
            boolean hasPermission) {
    public void pin(String pkg, SliceSpec[] specs, IBinder token) {
        synchronized (mLock) {
            if (mListeners.size() == 0) {
                mService.listen(mUri);
            }
            mListeners.put(token, new ListenerInfo(token, pkg, true,
                    Binder.getCallingUid(), Binder.getCallingPid()));
            try {
                listener.asBinder().linkToDeath(mDeathRecipient, 0);
                token.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
            }
            mListeners.put(listener.asBinder(), new ListenerInfo(listener, pkg, hasPermission,
                    Binder.getCallingUid(), Binder.getCallingPid()));
            mergeSpecs(specs);
            setSlicePinned(hasPermission);
        }
    }

    public boolean removeSliceListener(ISliceListener listener) {
        synchronized (mLock) {
            listener.asBinder().unlinkToDeath(mDeathRecipient, 0);
            if (mListeners.containsKey(listener.asBinder()) && mListeners.size() == 1) {
                mService.unlisten(mUri);
            }
            mListeners.remove(listener.asBinder());
        }
        return !hasPinOrListener();
    }

    public void pin(String pkg, SliceSpec[] specs) {
        synchronized (mLock) {
            setSlicePinned(true);
            mPinnedPkgs.add(pkg);
            mergeSpecs(specs);
        }
    }

    public boolean unpin(String pkg) {
    public boolean unpin(String pkg, IBinder token) {
        synchronized (mLock) {
            mPinnedPkgs.remove(pkg);
            token.unlinkToDeath(mDeathRecipient, 0);
            mListeners.remove(token);
        }
        return !hasPinOrListener();
    }
@@ -171,30 +144,6 @@ public class PinnedSliceState {
        }
    }

    public void recheckPackage(String pkg) {
        synchronized (mLock) {
            for (int i = 0; i < mListeners.size(); i++) {
                ListenerInfo info = mListeners.valueAt(i);
                if (!info.hasPermission && Objects.equals(info.pkg, pkg)) {
                    mService.getHandler().post(() -> {
                        // This bind lets the app itself participate in the permission grant.
                        Slice s = doBind(info);
                        if (mService.checkAccess(info.pkg, mUri, info.callingUid, info.callingPid)
                                == PERMISSION_GRANTED) {
                            info.hasPermission = true;
                            setSlicePinned(true);
                            try {
                                info.listener.onSliceUpdated(s);
                            } catch (RemoteException e) {
                                checkSelfRemove();
                            }
                        }
                    });
                }
            }
        }
    }

    @VisibleForTesting
    public boolean hasPinOrListener() {
        synchronized (mLock) {
@@ -213,7 +162,6 @@ public class PinnedSliceState {
    private void checkSelfRemove() {
        if (!hasPinOrListener()) {
            // All the listeners died, remove from pinned state.
            mService.unlisten(mUri);
            mService.removePinnedSlice(mUri);
        }
    }
@@ -223,70 +171,14 @@ public class PinnedSliceState {
        synchronized (mLock) {
            for (int i = mListeners.size() - 1; i >= 0; i--) {
                ListenerInfo l = mListeners.valueAt(i);
                if (!l.listener.asBinder().isBinderAlive()) {
                    mListeners.removeAt(i);
                }
            }
            checkSelfRemove();
        }
    }

    private void handleBind() {
        Slice cachedSlice = doBind(null);
        synchronized (mLock) {
            if (!hasPinOrListener()) return;
            for (int i = mListeners.size() - 1; i >= 0; i--) {
                ListenerInfo info = mListeners.valueAt(i);
                Slice s = cachedSlice;
                if (s == null || s.hasHint(Slice.HINT_CALLER_NEEDED)
                        || !info.hasPermission) {
                    s = doBind(info);
                }
                if (s == null) {
                    mListeners.removeAt(i);
                    continue;
                }
                try {
                    info.listener.onSliceUpdated(s);
                } catch (RemoteException e) {
                    Log.e(TAG, "Unable to notify slice " + mUri, e);
                if (!l.token.isBinderAlive()) {
                    mListeners.removeAt(i);
                    continue;
                }
            }
            checkSelfRemove();
        }
    }

    private Slice doBind(ListenerInfo info) {
        try (ContentProviderClient client = getClient()) {
            if (client == null) return null;
            Bundle extras = new Bundle();
            extras.putParcelable(SliceProvider.EXTRA_BIND_URI, mUri);
            extras.putParcelableArrayList(SliceProvider.EXTRA_SUPPORTED_SPECS,
                    new ArrayList<>(Arrays.asList(mSupportedSpecs)));
            if (info != null) {
                extras.putString(SliceProvider.EXTRA_OVERRIDE_PKG, info.pkg);
                extras.putInt(SliceProvider.EXTRA_OVERRIDE_UID, info.callingUid);
                extras.putInt(SliceProvider.EXTRA_OVERRIDE_PID, info.callingPid);
            }
            final Bundle res;
            try {
                res = client.call(SliceProvider.METHOD_SLICE, null, extras);
            } catch (RemoteException e) {
                Log.e(TAG, "Unable to bind slice " + mUri, e);
                return null;
            }
            if (res == null) return null;
            Bundle.setDefusable(res, true);
            return res.getParcelable(SliceProvider.EXTRA_SLICE);
        } catch (Throwable t) {
            // Calling out of the system process, make sure they don't throw anything at us.
            Log.e(TAG, "Caught throwable while binding " + mUri, t);
            return null;
        }
    }

    private void handleSendPinned() {
        try (ContentProviderClient client = getClient()) {
            if (client == null) return;
@@ -315,15 +207,15 @@ public class PinnedSliceState {

    private class ListenerInfo {

        private ISliceListener listener;
        private IBinder token;
        private String pkg;
        private boolean hasPermission;
        private int callingUid;
        private int callingPid;

        public ListenerInfo(ISliceListener listener, String pkg, boolean hasPermission,
        public ListenerInfo(IBinder token, String pkg, boolean hasPermission,
                int callingUid, int callingPid) {
            this.listener = listener;
            this.token = token;
            this.pkg = pkg;
            this.hasPermission = hasPermission;
            this.callingUid = callingUid;
+6 −61
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.ContentProviderHolder;
import android.app.IActivityManager;
import android.app.slice.ISliceListener;
import android.app.slice.ISliceManager;
import android.app.slice.SliceManager;
import android.app.slice.SliceSpec;
@@ -39,7 +38,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
@@ -52,7 +50,6 @@ import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.Log;
import android.util.Slog;
import android.util.Xml.Encoding;

@@ -94,7 +91,6 @@ public class SliceManagerService extends ISliceManager.Stub {
    @GuardedBy("mLock")
    private final ArraySet<SliceGrant> mUserGrants = new ArraySet<>();
    private final Handler mHandler;
    private final ContentObserver mObserver;
    @GuardedBy("mSliceAccessFile")
    private final AtomicFile mSliceAccessFile;
    @GuardedBy("mAccessList")
@@ -113,16 +109,6 @@ public class SliceManagerService extends ISliceManager.Stub {
        mAssistUtils = new AssistUtils(context);
        mHandler = new Handler(looper);

        mObserver = new ContentObserver(mHandler) {
            @Override
            public void onChange(boolean selfChange, Uri uri, int userId) {
                try {
                    getPinnedSlice(maybeAddUserId(uri, userId)).onChange();
                } catch (IllegalStateException e) {
                    Log.e(TAG, "Received change for unpinned slice " + uri, e);
                }
            }
        };
        final File systemDir = new File(Environment.getDataDirectory(), "system");
        mSliceAccessFile = new AtomicFile(new File(systemDir, "slice_access.xml"));
        mAccessList = new SliceFullAccessList(mContext);
@@ -163,40 +149,19 @@ public class SliceManagerService extends ISliceManager.Stub {

    ///  ----- ISliceManager stuff -----
    @Override
    public void addSliceListener(Uri uri, String pkg, ISliceListener listener, SliceSpec[] specs)
            throws RemoteException {
        verifyCaller(pkg);
        uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
        enforceCrossUser(pkg, uri);
        getOrCreatePinnedSlice(uri).addSliceListener(listener, pkg, specs,
                checkAccess(pkg, uri, Binder.getCallingUid(), Binder.getCallingUid())
                == PERMISSION_GRANTED);
    }

    @Override
    public void removeSliceListener(Uri uri, String pkg, ISliceListener listener)
            throws RemoteException {
        verifyCaller(pkg);
        uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
        if (getPinnedSlice(uri).removeSliceListener(listener)) {
            removePinnedSlice(uri);
        }
    }

    @Override
    public void pinSlice(String pkg, Uri uri, SliceSpec[] specs) throws RemoteException {
    public void pinSlice(String pkg, Uri uri, SliceSpec[] specs, IBinder token) throws RemoteException {
        verifyCaller(pkg);
        enforceFullAccess(pkg, "pinSlice", uri);
        enforceAccess(pkg, uri);
        uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
        getOrCreatePinnedSlice(uri).pin(pkg, specs);
        getOrCreatePinnedSlice(uri).pin(pkg, specs, token);
    }

    @Override
    public void unpinSlice(String pkg, Uri uri) throws RemoteException {
    public void unpinSlice(String pkg, Uri uri, IBinder token) throws RemoteException {
        verifyCaller(pkg);
        enforceFullAccess(pkg, "unpinSlice", uri);
        enforceAccess(pkg, uri);
        uri = maybeAddUserId(uri, Binder.getCallingUserHandle().getIdentifier());
        if (getPinnedSlice(uri).unpin(pkg)) {
        if (getPinnedSlice(uri).unpin(pkg, token)) {
            removePinnedSlice(uri);
        }
    }
@@ -253,11 +218,6 @@ public class SliceManagerService extends ISliceManager.Stub {
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        synchronized (mLock) {
            for (PinnedSliceState p : mPinnedSlicesByUri.values()) {
                p.recheckPackage(pkg);
            }
        }
    }

    // Backup/restore interface
@@ -457,21 +417,6 @@ public class SliceManagerService extends ISliceManager.Stub {
        return cn.getPackageName().equals(pkg);
    }

    public void listen(Uri uri) {
        mContext.getContentResolver().registerContentObserver(uri, true, mObserver);
    }

    public void unlisten(Uri uri) {
        mContext.getContentResolver().unregisterContentObserver(mObserver);
        synchronized (mLock) {
            mPinnedSlicesByUri.forEach((u, s) -> {
                if (s.isListening()) {
                    listen(u);
                }
            });
        }
    }

    private boolean isDefaultHomeApp(String pkg, int userId) {
        String defaultHome = getDefaultHome(userId);

Loading