Serenity Operating System
at hosted 196 lines 6.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "RemoteProcess.h" 28#include "RemoteObject.h" 29#include "RemoteObjectGraphModel.h" 30#include "RemoteObjectPropertyModel.h" 31#include <stdio.h> 32#include <stdlib.h> 33 34RemoteProcess* s_the; 35 36RemoteProcess& RemoteProcess::the() 37{ 38 return *s_the; 39} 40 41RemoteProcess::RemoteProcess(pid_t pid) 42 : m_pid(pid) 43 , m_object_graph_model(RemoteObjectGraphModel::create(*this)) 44 , m_socket(Core::LocalSocket::construct()) 45{ 46 s_the = this; 47 m_socket->set_blocking(true); 48} 49 50void RemoteProcess::handle_identify_response(const JsonObject& response) 51{ 52 int pid = response.get("pid").to_int(); 53 ASSERT(pid == m_pid); 54 55 m_process_name = response.get("process_name").as_string_or({}); 56 57 if (on_update) 58 on_update(); 59} 60 61void RemoteProcess::handle_get_all_objects_response(const JsonObject& response) 62{ 63 // FIXME: It would be good if we didn't have to make a local copy of the array value here! 64 auto objects = response.get("objects"); 65 auto& object_array = objects.as_array(); 66 67 NonnullOwnPtrVector<RemoteObject> remote_objects; 68 HashMap<FlatPtr, RemoteObject*> objects_by_address; 69 70 for (auto& value : object_array.values()) { 71 ASSERT(value.is_object()); 72 auto& object = value.as_object(); 73 auto remote_object = make<RemoteObject>(); 74 remote_object->address = object.get("address").to_number<FlatPtr>(); 75 remote_object->parent_address = object.get("parent").to_number<FlatPtr>(); 76 remote_object->name = object.get("name").to_string(); 77 remote_object->class_name = object.get("class_name").to_string(); 78 remote_object->json = object; 79 objects_by_address.set(remote_object->address, remote_object); 80 remote_objects.append(move(remote_object)); 81 } 82 83 for (size_t i = 0; i < remote_objects.size(); ++i) { 84 auto& remote_object = remote_objects.ptr_at(i); 85 auto* parent = objects_by_address.get(remote_object->parent_address).value_or(nullptr); 86 if (!parent) { 87 m_roots.append(move(remote_object)); 88 } else { 89 remote_object->parent = parent; 90 parent->children.append(move(remote_object)); 91 } 92 } 93 94 m_object_graph_model->update(); 95 96 if (on_update) 97 on_update(); 98} 99 100void RemoteProcess::send_request(const JsonObject& request) 101{ 102 auto serialized = request.to_string(); 103 i32 length = serialized.length(); 104 m_socket->write((const u8*)&length, sizeof(length)); 105 m_socket->write(serialized); 106} 107 108void RemoteProcess::set_inspected_object(FlatPtr address) 109{ 110 JsonObject request; 111 request.set("type", "SetInspectedObject"); 112 request.set("address", address); 113 send_request(request); 114} 115 116void RemoteProcess::set_property(FlatPtr object, const StringView& name, const JsonValue& value) 117{ 118 JsonObject request; 119 request.set("type", "SetProperty"); 120 request.set("address", object); 121 request.set("name", JsonValue(name)); 122 request.set("value", value); 123 send_request(request); 124} 125 126void RemoteProcess::update() 127{ 128 m_socket->on_connected = [this] { 129 dbg() << "Connected to PID " << m_pid; 130 131 { 132 JsonObject request; 133 request.set("type", "Identify"); 134 send_request(request); 135 } 136 137 { 138 JsonObject request; 139 request.set("type", "GetAllObjects"); 140 send_request(request); 141 } 142 }; 143 144 m_socket->on_ready_to_read = [this] { 145 if (m_socket->eof()) { 146 dbg() << "Disconnected from PID " << m_pid; 147 m_socket->close(); 148 return; 149 } 150 151 u32 length; 152 int nread = m_socket->read((u8*)&length, sizeof(length)); 153 ASSERT(nread == sizeof(length)); 154 155 ByteBuffer data; 156 size_t remaining_bytes = length; 157 158 while (remaining_bytes) { 159 auto packet = m_socket->read(remaining_bytes); 160 if (packet.size() == 0) 161 break; 162 data.append(packet.data(), packet.size()); 163 remaining_bytes -= packet.size(); 164 } 165 166 ASSERT(data.size() == length); 167 dbg() << "Got data size " << length << " and read that many bytes"; 168 169 auto json_value = JsonValue::from_string(data); 170 ASSERT(json_value.is_object()); 171 172 dbg() << "Got JSON response " << json_value.to_string(); 173 174 auto& response = json_value.as_object(); 175 176 auto response_type = response.get("type").as_string_or({}); 177 if (response_type.is_null()) 178 return; 179 180 if (response_type == "GetAllObjects") { 181 handle_get_all_objects_response(response); 182 return; 183 } 184 185 if (response_type == "Identify") { 186 handle_identify_response(response); 187 return; 188 } 189 }; 190 191 auto success = m_socket->connect(Core::SocketAddress::local(String::format("/tmp/rpc.%d", m_pid))); 192 if (!success) { 193 fprintf(stderr, "Couldn't connect to PID %d\n", m_pid); 194 exit(1); 195 } 196}