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

Commit b3b22cba authored by Svet Ganov's avatar Svet Ganov Committed by Svetoslav Ganov
Browse files

Prevent apps to overlay other apps via toast windows

It was possible for apps to put toast type windows
that overlay other apps which toast winodws aren't
removed after a timeout like toasts are.

Now to add a toast window one needs to have a special
token. The token is added by the notificatoion manager
service only for the lifetime of the shown toast and
is then removed including all windows associated with
this token.

This prevents apps to add arbitrary toast windows. The
token is passed in the app domain in the request to
construt and add the toast window which allows a bad
app to add arbitrary toast windows. However, this is
fine since the token will be invalided and all of its
windows removed after the toast for which it was
create times out.

We do not care of braking apps that add toast windows
directly due to the security and privacy implications
of arbitrary UI redressing. Also we have dedicated
Toast APIs which are the way to add this time of UI.

bug:30150688

Change-Id: I65372c81a791489de89fb2886cc96392c28680bb
parent 18513144
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@ package android.app;

/** @hide */
oneway interface ITransientNotification {
    void show();
    void show(IBinder windowToken);
    void hide();
}
+14 −11
Original line number Diff line number Diff line
@@ -24,7 +24,10 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
@@ -326,13 +329,6 @@ public class Toast {
    }

    private static class TN extends ITransientNotification.Stub {
        final Runnable mShow = new Runnable() {
            @Override
            public void run() {
                handleShow();
            }
        };

        final Runnable mHide = new Runnable() {
            @Override
            public void run() {
@@ -343,7 +339,13 @@ public class Toast {
        };

        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
        final Handler mHandler = new Handler();
        final Handler mHandler = new Handler() {
            @Override
            public void handleMessage(Message msg) {
                IBinder token = (IBinder) msg.obj;
                handleShow(token);
            }
        };

        int mGravity;
        int mX, mY;
@@ -379,9 +381,9 @@ public class Toast {
         * schedule handleShow into the right thread
         */
        @Override
        public void show() {
        public void show(IBinder windowToken) {
            if (localLOGV) Log.v(TAG, "SHOW: " + this);
            mHandler.post(mShow);
            mHandler.obtainMessage(0, windowToken).sendToTarget();
        }

        /**
@@ -393,7 +395,7 @@ public class Toast {
            mHandler.post(mHide);
        }

        public void handleShow() {
        public void handleShow(IBinder windowToken) {
            if (localLOGV) Log.v(TAG, "HANDLE SHOW: " + this + " mView=" + mView
                    + " mNextView=" + mNextView);
            if (mView != mNextView) {
@@ -424,6 +426,7 @@ public class Toast {
                mParams.packageName = packageName;
                mParams.removeTimeoutMilliseconds = mDuration ==
                    Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
                mParams.token = windowToken;
                if (mView.getParent() != null) {
                    if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                    mWM.removeView(mView);
+21 −11
Original line number Diff line number Diff line
@@ -58,7 +58,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.NotificationManager.Policy;
import android.app.PendingIntent;
import android.app.RemoteInput;
import android.app.StatusBarManager;
import android.app.backup.BackupManager;
import android.app.usage.UsageEvents;
@@ -93,7 +92,6 @@ import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.Message;
import android.os.Parcelable;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -122,6 +120,8 @@ import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.Xml;
import android.view.WindowManager;
import android.view.WindowManagerInternal;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
@@ -232,6 +232,7 @@ public class NotificationManagerService extends SystemService {
    @Nullable StatusBarManagerInternal mStatusBar;
    Vibrator mVibrator;
    private VrManagerInternal mVrManagerInternal;
    private WindowManagerInternal mWindowManagerInternal;

    final IBinder mForegroundToken = new Binder();
    private Handler mHandler;
@@ -452,13 +453,15 @@ public class NotificationManagerService extends SystemService {
        final String pkg;
        final ITransientNotification callback;
        int duration;
        Binder token;

        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration)
        {
        ToastRecord(int pid, String pkg, ITransientNotification callback, int duration,
                    Binder token) {
            this.pid = pid;
            this.pkg = pkg;
            this.callback = callback;
            this.duration = duration;
            this.token = token;
        }

        void update(int duration) {
@@ -1125,6 +1128,7 @@ public class NotificationManagerService extends SystemService {
            mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
            mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
            mVrManagerInternal = getLocalService(VrManagerInternal.class);
            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
            mZenModeHelper.onSystemReady();
        } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
            // This observer will force an update when observe is called, causing us to
@@ -1325,10 +1329,13 @@ public class NotificationManagerService extends SystemService {
                            }
                        }

                        record = new ToastRecord(callingPid, pkg, callback, duration);
                        Binder token = new Binder();
                        mWindowManagerInternal.addWindowToken(token,
                                WindowManager.LayoutParams.TYPE_TOAST);
                        record = new ToastRecord(callingPid, pkg, callback, duration, token);
                        mToastQueue.add(record);
                        index = mToastQueue.size() - 1;
                        keepProcessAliveLocked(callingPid);
                        keepProcessAliveIfNeededLocked(callingPid);
                    }
                    // If it's at index 0, it's the current toast.  It doesn't matter if it's
                    // new or just been updated.  Call back and tell it to show itself.
@@ -2987,7 +2994,7 @@ public class NotificationManagerService extends SystemService {
        while (record != null) {
            if (DBG) Slog.d(TAG, "Show pkg=" + record.pkg + " callback=" + record.callback);
            try {
                record.callback.show();
                record.callback.show(record.token);
                scheduleTimeoutLocked(record);
                return;
            } catch (RemoteException e) {
@@ -2998,7 +3005,7 @@ public class NotificationManagerService extends SystemService {
                if (index >= 0) {
                    mToastQueue.remove(index);
                }
                keepProcessAliveLocked(record.pid);
                keepProcessAliveIfNeededLocked(record.pid);
                if (mToastQueue.size() > 0) {
                    record = mToastQueue.get(0);
                } else {
@@ -3018,8 +3025,11 @@ public class NotificationManagerService extends SystemService {
            // don't worry about this, we're about to remove it from
            // the list anyway
        }
        mToastQueue.remove(index);
        keepProcessAliveLocked(record.pid);

        ToastRecord lastToast = mToastQueue.remove(index);
        mWindowManagerInternal.removeWindowToken(lastToast.token, true);

        keepProcessAliveIfNeededLocked(record.pid);
        if (mToastQueue.size() > 0) {
            // Show the next one. If the callback fails, this will remove
            // it from the list, so don't assume that the list hasn't changed
@@ -3063,7 +3073,7 @@ public class NotificationManagerService extends SystemService {
    }

    // lock on mToastQueue
    void keepProcessAliveLocked(int pid)
    void keepProcessAliveIfNeededLocked(int pid)
    {
        int toastCount = 0; // toasts from this pid
        ArrayList<ToastRecord> list = mToastQueue;
+12 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
@@ -1950,6 +1951,11 @@ public class WindowManagerService extends IWindowManager.Stub
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                if (type == TYPE_TOAST) {
                    Slog.w(TAG_WM, "Attempted to add a toast window with unknown token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
                token = new WindowToken(this, attrs.token, -1, false);
                addToken = true;
            } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
@@ -1999,6 +2005,12 @@ public class WindowManagerService extends IWindowManager.Stub
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_TOAST) {
                if (token.windowType != TYPE_TOAST) {
                    Slog.w(TAG_WM, "Attempted to add a toast window with bad token "
                            + attrs.token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                }
            } else if (type == TYPE_QS_DIALOG) {
                if (token.windowType != TYPE_QS_DIALOG) {
                    Slog.w(TAG_WM, "Attempted to add QS dialog window with bad token "