summaryrefslogtreecommitdiff
path: root/core/java/android/os/RemoteCallback.java
diff options
context:
space:
mode:
authorSvet Ganov <svetoslavganov@google.com>2015-12-01 19:52:26 -0800
committerSvetoslav Ganov <svetoslavganov@google.com>2015-12-02 04:23:02 +0000
commit9c165d76010d9f79f5cd71978742a335b6b8d1b4 (patch)
treec0640aa867a555f43e73b252b799673f3a05460b /core/java/android/os/RemoteCallback.java
parent8390b2ac85765e768d4b685077a96e6395d208b4 (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.java120
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) {