1/* Copyright (C) 2010 The Android Open Source Project
2**
3** This software is licensed under the terms of the GNU General Public
4** License version 2, as published by the Free Software Foundation, and
5** may be copied, distributed, and modified under those terms.
6**
7** This program is distributed in the hope that it will be useful,
8** but WITHOUT ANY WARRANTY; without even the implied warranty of
9** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10** GNU General Public License for more details.
11*/
12
13/*
14 * Contains the Core-side implementation of the "attach-ui" service that is
15 * used to establish connection between the UI and the Core.
16 */
17
18#include "android/android.h"
19#include "android/globals.h"
20#include "android/looper.h"
21#include "android/async-utils.h"
22#include "android/sync-utils.h"
23#include "android/utils/debug.h"
24#include "android/protocol/core-commands.h"
25#include "android/protocol/core-commands-impl.h"
26
27/* Descriptor for the UI attach-ui proxy. */
28typedef struct AttachUIProxy {
29    /* Reader to detect UI disconnection. */
30    AsyncReader         async_reader;
31
32    /* I/O associated with this descriptor. */
33    LoopIo              io;
34
35    /* Looper used to communicate with the UI. */
36    Looper*             looper;
37
38    /* Socket descriptor for this service. */
39    int                 sock;
40} AttachUIProxy;
41
42/* One and only one AttachUIProxy instance. */
43static AttachUIProxy    _attachUiProxy;
44
45/* Implemented in android/console.c */
46extern void destroy_attach_ui_client(void);
47
48/* Asynchronous I/O callback for AttachUIProxy instance.
49 * We expect this callback to be called only on UI detachment condition. In this
50 * case the event should be LOOP_IO_READ, and read should fail with errno set
51 * to ECONNRESET.
52 * Param:
53 *  opaque - AttachUIProxy instance.
54 */
55static void
56_attachUiProxy_io_func(void* opaque, int fd, unsigned events)
57{
58    AttachUIProxy* uicmd = (AttachUIProxy*)opaque;
59    AsyncReader reader;
60    AsyncStatus status;
61    uint8_t read_buf[1];
62
63    if (events & LOOP_IO_WRITE) {
64        derror("Unexpected LOOP_IO_WRITE in _attachUiProxy_io_func.\n");
65        return;
66    }
67
68    // Try to read
69    asyncReader_init(&reader, read_buf, sizeof(read_buf), &uicmd->io);
70    status = asyncReader_read(&reader);
71    // We expect only error status here.
72    if (status != ASYNC_ERROR) {
73        derror("Unexpected read status %d in _attachUiProxy_io_func\n", status);
74        return;
75    }
76    // We expect only socket disconnection error here.
77    if (errno != ECONNRESET) {
78        derror("Unexpected read error %d (%s) in _attachUiProxy_io_func.\n",
79               errno, errno_str);
80        return;
81    }
82
83    // Client got disconnectted.
84    destroy_attach_ui_client();
85}
86
87int
88attachUiProxy_create(int fd)
89{
90    // Initialize the only AttachUIProxy instance.
91    _attachUiProxy.sock = fd;
92    _attachUiProxy.looper = looper_newCore();
93    loopIo_init(&_attachUiProxy.io, _attachUiProxy.looper, _attachUiProxy.sock,
94                _attachUiProxy_io_func, &_attachUiProxy);
95    loopIo_wantRead(&_attachUiProxy.io);
96
97    return 0;
98}
99
100void
101attachUiProxy_destroy(void)
102{
103    if (_attachUiProxy.looper != NULL) {
104        // Stop all I/O that may still be going on.
105        loopIo_done(&_attachUiProxy.io);
106        looper_free(_attachUiProxy.looper);
107        _attachUiProxy.looper = NULL;
108    }
109    _attachUiProxy.sock = -1;
110}
111