diff options
| author | Svet Ganov <svetoslavganov@google.com> | 2015-12-01 19:52:26 -0800 |
|---|---|---|
| committer | Svetoslav Ganov <svetoslavganov@google.com> | 2015-12-02 04:23:02 +0000 |
| commit | 9c165d76010d9f79f5cd71978742a335b6b8d1b4 (patch) | |
| tree | c0640aa867a555f43e73b252b799673f3a05460b /core/java/android/os/RemoteCallback.java | |
| parent | 8390b2ac85765e768d4b685077a96e6395d208b4 (diff) | |
Add optional permission review for legacy apps - framework
For some markets we have to allow the user to review permissions
for legacy apps at runtime despite them not supporting the new
permission model. This is achieved by showing a review UI before
launching any app component. If an update is installed the user
should see a permission review UI for the newly requested
permissions.
To allow distinguishing which permissions need a review we set
a special flag in the permission flags that a review is required.
This flag is set if a runtime permission is granted to a legacy
app and the system does not launch any app components until this
flag is cleared. Since install permissions are shared across all
users the dangerous permissions for legacy apps in review mode
are represented as always granted runtime permissions since the
reivew requirement is on a per user basis.
Whether the build supports permission review for legacy apps is
determined by a build constant allowing us to compile away the
unnecessary code for markets that do not require a permissions
review.
If an app launches an activity in another app that has some
permissions needing review, we launch the permissions review
UI and pass it a pending intent to launch the activity after
the review is completed.
If an app sends a broadcast to another app that has some permissions
needing review, we do not deliver the broadcast and if the sending
app is in the foreground plus the broadcast is explicit (has a
component) we launch the review UI giving it a pending intent to
send the broadcast after the review is completed.
If an app starts a service in another app that has some permissions
needing review, we do not start the service and if the calling app
is in the foreground we launch the review UI and pass it a pending
intent to start the service after the review is completed.
If an app binds to a service in another app that has some permissions
needing review, we schedule the binding but do not spin the target
service's process and we launch the review UI and pass it a callback
to invoke after the review is completed which spins the service
process and completes the binding.
If an app requests a content provider in another app that has some
permissions needing review we do not return the provider and if
the calling app is in the foreground we show the review UI.
Change-Id: I550f5ff6cadc46a98a1d1a7b8415eca551203acf
Diffstat (limited to 'core/java/android/os/RemoteCallback.java')
| -rw-r--r-- | core/java/android/os/RemoteCallback.java | 120 |
1 files changed, 58 insertions, 62 deletions
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java index ca95bdf529cd..89e30a96f65d 100644 --- a/core/java/android/os/RemoteCallback.java +++ b/core/java/android/os/RemoteCallback.java @@ -16,88 +16,84 @@ package android.os; +import android.annotation.NonNull; +import android.annotation.Nullable; + /** - * TODO: Make this a public API? Let's see how it goes with a few use - * cases first. * @hide */ -public abstract class RemoteCallback implements Parcelable { - final Handler mHandler; - final IRemoteCallback mTarget; - - class DeliverResult implements Runnable { - final Bundle mResult; - - DeliverResult(Bundle result) { - mResult = result; - } - - public void run() { - onResult(mResult); - } +public final class RemoteCallback implements Parcelable { + + public interface OnResultListener { + public void onResult(Bundle result); } - - class LocalCallback extends IRemoteCallback.Stub { - public void sendResult(Bundle bundle) { - mHandler.post(new DeliverResult(bundle)); - } + + private final OnResultListener mListener; + private final Handler mHandler; + private final IRemoteCallback mCallback; + + public RemoteCallback(OnResultListener listener) { + this(listener, null); } - - static class RemoteCallbackProxy extends RemoteCallback { - RemoteCallbackProxy(IRemoteCallback target) { - super(target); - } - - protected void onResult(Bundle bundle) { + + public RemoteCallback(@NonNull OnResultListener listener, @Nullable Handler handler) { + if (listener == null) { + throw new NullPointerException("listener cannot be null"); } - } - - public RemoteCallback(Handler handler) { + mListener = listener; mHandler = handler; - mTarget = new LocalCallback(); + mCallback = new IRemoteCallback.Stub() { + @Override + public void sendResult(Bundle data) { + RemoteCallback.this.sendResult(data); + } + }; } - - RemoteCallback(IRemoteCallback target) { + + RemoteCallback(Parcel parcel) { + mListener = null; mHandler = null; - mTarget = target; - } - - public void sendResult(Bundle bundle) throws RemoteException { - mTarget.sendResult(bundle); + mCallback = IRemoteCallback.Stub.asInterface( + parcel.readStrongBinder()); } - - protected abstract void onResult(Bundle bundle); - - public boolean equals(Object otherObj) { - if (otherObj == null) { - return false; - } - try { - return mTarget.asBinder().equals(((RemoteCallback)otherObj) - .mTarget.asBinder()); - } catch (ClassCastException e) { + + public void sendResult(@Nullable final Bundle result) { + // Do local dispatch + if (mListener != null) { + if (mHandler != null) { + mHandler.post(new Runnable() { + @Override + public void run() { + mListener.onResult(result); + } + }); + } else { + mListener.onResult(result); + } + // Do remote dispatch + } else { + try { + mCallback.sendResult(result); + } catch (RemoteException e) { + /* ignore */ + } } - return false; } - - public int hashCode() { - return mTarget.asBinder().hashCode(); - } - + + @Override public int describeContents() { return 0; } - public void writeToParcel(Parcel out, int flags) { - out.writeStrongBinder(mTarget.asBinder()); + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeStrongBinder(mCallback.asBinder()); } public static final Parcelable.Creator<RemoteCallback> CREATOR = new Parcelable.Creator<RemoteCallback>() { - public RemoteCallback createFromParcel(Parcel in) { - IBinder target = in.readStrongBinder(); - return target != null ? new RemoteCallbackProxy( - IRemoteCallback.Stub.asInterface(target)) : null; + public RemoteCallback createFromParcel(Parcel parcel) { + return new RemoteCallback(parcel); } public RemoteCallback[] newArray(int size) { |
