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

Commit 6ae1d3b6 authored by Andy Mast's avatar Andy Mast
Browse files

*DO NOT SUBMIT* Allow screenshots through 3rd party apps

This is for internal use only. Do not submit as a patch
for the general public as it has security holes.

For emulator instances where screencap does not work,
one can use this patch to allow 3rd party applications
to take a screenshot. It uses the same code as HiearchyViewer
but with ParcelFileDescriptors instead. The client side
should make the call on a separate thread from the reader
of the PFD so that the app does not get blocked.

Change-Id: I5bfb210e07aacc56e46e87cbe88ed31e73c61f83
parent de75b0da
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@ import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.os.IRemoteCallback;
import android.os.ParcelFileDescriptor;
import android.view.IApplicationToken;
import android.view.IApplicationToken;
import android.view.IOnKeyguardExitResult;
import android.view.IOnKeyguardExitResult;
import android.view.IRotationWatcher;
import android.view.IRotationWatcher;
@@ -279,4 +280,8 @@ interface IWindowManager
     * @return The frame statistics or null if the window does not exist.
     * @return The frame statistics or null if the window does not exist.
     */
     */
    WindowContentFrameStats getWindowContentFrameStats(IBinder token);
    WindowContentFrameStats getWindowContentFrameStats(IBinder token);

    String viewServerListWindows2();

    String viewServerWindowCommand2(in ParcelFileDescriptor fd, String command, String parameters);
}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -315,6 +315,7 @@ public class ViewDebug {
    private static final int CAPTURE_TIMEOUT = 4000;
    private static final int CAPTURE_TIMEOUT = 4000;


    private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
    private static final String REMOTE_COMMAND_CAPTURE = "CAPTURE";
    private static final String REMOTE_COMMAND_CAPTURE_ROOT = "CAPTURE_ROOT";
    private static final String REMOTE_COMMAND_DUMP = "DUMP";
    private static final String REMOTE_COMMAND_DUMP = "DUMP";
    private static final String REMOTE_COMMAND_DUMP_THEME = "DUMP_THEME";
    private static final String REMOTE_COMMAND_DUMP_THEME = "DUMP_THEME";
    private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
    private static final String REMOTE_COMMAND_INVALIDATE = "INVALIDATE";
@@ -440,6 +441,8 @@ public class ViewDebug {
            final String[] params = parameters.split(" ");
            final String[] params = parameters.split(" ");
            if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
            if (REMOTE_COMMAND_CAPTURE.equalsIgnoreCase(command)) {
                capture(view, clientStream, params[0]);
                capture(view, clientStream, params[0]);
            } else if (REMOTE_COMMAND_CAPTURE_ROOT.equalsIgnoreCase(command)) {
                capture(view, clientStream, view);
            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
            } else if (REMOTE_COMMAND_OUTPUT_DISPLAYLIST.equalsIgnoreCase(command)) {
                outputDisplayList(view, params[0]);
                outputDisplayList(view, params[0]);
            } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
            } else if (REMOTE_COMMAND_INVALIDATE.equalsIgnoreCase(command)) {
+20 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Build;
import android.os.IBinder;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.SystemProperties;
@@ -35,6 +36,7 @@ import com.android.internal.util.FastPrintWriter;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.FileOutputStream;
import java.io.PrintWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.ArrayList;


/**
/**
@@ -550,6 +552,24 @@ public final class WindowManagerGlobal {
            }
            }
        }
        }
    }
    }

    public static String viewServerListWindows() {
        try {
            return sWindowManagerService.viewServerListWindows2();
        } catch(RemoteException e) {
            Log.e(TAG, "Could not viewServerListWindows", e);
        }
        return null;
    }

    public static String viewServerWindowCommand(ParcelFileDescriptor fd, String command, String parameters) {
        try {
            return sWindowManagerService.viewServerWindowCommand2(fd, command, parameters);
        } catch(RemoteException e) {
            Log.e(TAG, "Could not viewServerListWIndows ", e);
        }
        return null;
    }
}
}


final class WindowLeaked extends AndroidRuntimeException {
final class WindowLeaked extends AndroidRuntimeException {
+115 −0
Original line number Original line Diff line number Diff line
@@ -146,6 +146,7 @@ import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.OutputStreamWriter;
@@ -6934,6 +6935,41 @@ public class WindowManagerService extends IWindowManager.Stub
        return mViewServer != null && mViewServer.isRunning();
        return mViewServer != null && mViewServer.isRunning();
    }
    }
    public String viewServerListWindows2() {
        boolean result = true;
        WindowList windows = new WindowList();
        synchronized (mWindowMap) {
            //noinspection unchecked
            final int numDisplays = mDisplayContents.size();
            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
                windows.addAll(displayContent.getWindowList());
            }
        }
        // Any uncaught exception will crash the system process
        StringBuffer sb = new StringBuffer();
        try {
            final int count = windows.size();
            for (int i = 0; i < count; i++) {
                final WindowState w = windows.get(i);
                sb.append(Integer.toHexString(System.identityHashCode(w)));
                sb.append(' ');
                sb.append(w.mAttrs.getTitle());
                sb.append('\n');
            }
            sb.append("DONE.\n");
        } catch (Exception e) {
            result = false;
        }
        return sb.toString();
    }
    /**
    /**
     * Lists all availble windows in the system. The listing is written in the
     * Lists all availble windows in the system. The listing is written in the
     * specified Socket's output stream with the following syntax:
     * specified Socket's output stream with the following syntax:
@@ -7135,6 +7171,85 @@ public class WindowManagerService extends IWindowManager.Stub
        return success;
        return success;
    }
    }
    public String viewServerWindowCommand2(ParcelFileDescriptor fd, String command, String parameters) {
        if (isSystemSecure()) {
            return null;
        }
        boolean success = true;
        Parcel data = null;
        Parcel reply = null;
        BufferedWriter out = null;
        // Any uncaught exception will crash the system process
        try {
            // Find the hashcode of the window
            int index = parameters.indexOf(' ');
            if (index == -1) {
                index = parameters.length();
            }
            final String code = parameters.substring(0, index);
            int hashCode = (int) Long.parseLong(code, 16);
            // Extract the command's parameter after the window description
            if (index < parameters.length()) {
                parameters = parameters.substring(index + 1);
            } else {
                parameters = "";
            }
            final WindowState window = findWindow(hashCode);
            if (window == null) {
                return null;
            }
            data = Parcel.obtain();
            data.writeInterfaceToken("android.view.IWindow");
            data.writeString(command);
            data.writeString(parameters);
            data.writeInt(1);
            //ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliableSocketPair();
            fd.writeToParcel(data, 0);
            reply = Parcel.obtain();
            final IBinder binder = window.mClient.asBinder();
            // TODO: GET THE TRANSACTION CODE IN A SAFER MANNER
            binder.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
            reply.readException();
            //FileOutputStream appendOut = new FileOutputStream(fd.getFileDescriptor());
            //OutputStreamWriter writer = new OutputStreamWriter(appendOut);
            //writer.write("DONE\n");
            //writer.close();
            //appendOut.flush();
            //appendOut.close();
        } catch (Exception e) {
            Slog.w(TAG, "Could not send command " + command + " with parameters " + parameters, e);
            success = false;
        } finally {
            if (data != null) {
                data.recycle();
            }
            if (reply != null) {
                reply.recycle();
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }
        }
        return "";
    }
    public void addWindowChangeListener(WindowChangeListener listener) {
    public void addWindowChangeListener(WindowChangeListener listener) {
        synchronized(mWindowMap) {
        synchronized(mWindowMap) {
            mWindowChangeListeners.add(listener);
            mWindowChangeListeners.add(listener);