2014. 7. 24. 07:29

The process of the hierarchy dump in android

The simple overview of ui dump process in android is like the following figure:

(2 years ago, I was involved in the project that developed the android test automation tool.)





The related source code is as below:


-----------------------------------------------------------------------------------

ViewServer.java

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/master/services/java/com/android/server/wm/ViewServer.java



class ViewServer implements Runnable {


    private final WindowManagerService mWindowManager;


    class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener {

        private Socket mClient;

        private boolean mNeedWindowListUpdate;

        private boolean mNeedFocusedWindowUpdate;

        public ViewServerWorker(Socket client) {

            mClient = client;

            mNeedWindowListUpdate = false;

            mNeedFocusedWindowUpdate = false;

        }

        public void run() {

            BufferedReader in = null;

            try {

                in = new BufferedReader(new InputStreamReader(mClient.getInputStream()), 1024);

                final String request = in.readLine();

                String command;

                String parameters;

                int index = request.indexOf(' ');

                if (index == -1) {

                    command = request;

                    parameters = "";

                } else {

                    command = request.substring(0, index);

                    parameters = request.substring(index + 1);

                }

                boolean result;

                if (COMMAND_PROTOCOL_VERSION.equalsIgnoreCase(command)) {

                    result = writeValue(mClient, VALUE_PROTOCOL_VERSION);

                } else if (COMMAND_SERVER_VERSION.equalsIgnoreCase(command)) {

                    result = writeValue(mClient, VALUE_SERVER_VERSION);

                } else if (COMMAND_WINDOW_MANAGER_LIST.equalsIgnoreCase(command)) {

                    result = mWindowManager.viewServerListWindows(mClient);

                } else if (COMMAND_WINDOW_MANAGER_GET_FOCUS.equalsIgnoreCase(command)) {

                    result = mWindowManager.viewServerGetFocusedWindow(mClient);

                } else if (COMMAND_WINDOW_MANAGER_AUTOLIST.equalsIgnoreCase(command)) {

                    result = windowManagerAutolistLoop();

                } else {

                    result = mWindowManager.viewServerWindowCommand(mClient,command, parameters);

                }

   // ...

}

    }

}


-----------------------------------------------------------------------------------

WindowManagerService.java

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/master/services/java/com/android/server/wm/WindowManagerService.java



public class WindowManagerService extends IWindowManager.Stub

        implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs,

                DisplayManagerService.WindowManagerFuncs, DisplayManager.DisplayListener {


    boolean viewServerWindowCommand(Socket client, String command, String parameters) {


        // 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 false;

            }

            data = Parcel.obtain();

            data.writeInterfaceToken("android.view.IWindow");

            data.writeString(command);

            data.writeString(parameters);

            data.writeInt(1);

            ParcelFileDescriptor.fromSocket(client).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);


}

}


-----------------------------------------------------------------------------------

WindowState.java

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/master/services/java/com/android/server/wm/WindowState.java


import android.view.IWindow;


final class WindowState implements WindowManagerPolicy.WindowState {


    final IWindow mClient;


}


-----------------------------------------------------------------------------------

IWindow.aidl

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/com/android/internal/view/BaseIWindow.java


oneway interface IWindow {

    void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor);

}


-----------------------------------------------------------------------------------

ViewRootImpl.java

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/17d28ca/core/java/android/view/ViewRootImpl.java


public final class ViewRootImpl implements ViewParent,

        View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {


    static class W extends IWindow.Stub {

        @Override

        public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {

            final ViewRootImpl viewAncestor = mViewAncestor.get();

            if (viewAncestor != null) {

                final View view = viewAncestor.mView;

                if (view != null) {

                    if (checkCallingPermission(Manifest.permission.DUMP) !=

                            PackageManager.PERMISSION_GRANTED) {

                        throw new SecurityException("Insufficient permissions to invoke"

                                + " executeCommand() from pid=" + Binder.getCallingPid()

                                + ", uid=" + Binder.getCallingUid());

                    }

                    OutputStream clientStream = null;

                    try {

                        clientStream = new ParcelFileDescriptor.AutoCloseOutputStream(out);

                        ViewDebug.dispatchCommand(view, command, parameters, clientStream);

                    } catch (IOException e) {

                        e.printStackTrace();

                    } finally {

                        if (clientStream != null) {

                            try {

                                clientStream.close();

                            } catch (IOException e) {

                                e.printStackTrace();

                            }

                        }

                    }

                }

            }

        }

    }


}



-----------------------------------------------------------------------------------

ViewDebug.java

-----------------------------------------------------------------------------------

https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/ViewDebug.java


/**

 * Various debugging/tracing tools related to {@link View} and the view hierarchy.

 */

class ViewDebug

{

void dispatchCommand(View view, String command, String parameters,

            OutputStream clientStream) throws IOException {

        if (REMOTE_COMMAND_DUMP.equalsIgnoreCase(command)) {

            dump(view, false, true, clientStream);

}




    /**

     * Dumps the view hierarchy starting from the given view.

     * @hide

     */

    public static void dump(View root, boolean skipChildren, boolean includeProperties,

            OutputStream clientStream) throws IOException {

        BufferedWriter out = null;

        try {

            out = new BufferedWriter(new OutputStreamWriter(clientStream, "utf-8"), 32 * 1024);

            View view = root.getRootView();

            if (view instanceof ViewGroup) {

                ViewGroup group = (ViewGroup) view;

                dumpViewHierarchy(group.getContext(), group, out, 0,

                        skipChildren, includeProperties);

            }

            out.write("DONE.");

            out.newLine();

        } catch (Exception e) {

            android.util.Log.w("View", "Problem dumping the view:", e);

        } finally {

            if (out != null) {

                out.close();

            }

        }

    }


    private static void dumpViewHierarchy(Context context, ViewGroup group,

            BufferedWriter out, int level, boolean skipChildren, boolean includeProperties) {

        if (!dumpView(context, group, out, level, includeProperties)) {

            return;

        }

        if (skipChildren) {

            return;

        }

        final int count = group.getChildCount();

        for (int i = 0; i < count; i++) {

            final View view = group.getChildAt(i);

            if (view instanceof ViewGroup) {

                dumpViewHierarchy(context, (ViewGroup) view, out, level + 1, skipChildren,

                        includeProperties);

            } else {

                dumpView(context, view, out, level + 1, includeProperties);

            }

            if (view.mOverlay != null) {

                ViewOverlay overlay = view.getOverlay();

                ViewGroup overlayContainer = overlay.mOverlayViewGroup;

                dumpViewHierarchy(context, overlayContainer, out, level + 2, skipChildren,

                        includeProperties);

            }

        }

        if (group instanceof HierarchyHandler) {

            ((HierarchyHandler)group).dumpViewHierarchyWithProperties(out, level + 1);

        }

    } 


}