1 // Copyright 2019 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "host-common/address_space_device.h"
15 #include "host-common/AddressSpaceService.h"
16 #include "host-common/address_space_graphics.h"
17 #ifndef AEMU_MIN
18 #include "host-common/address_space_host_media.h"
19 #endif
20 #include "host-common/address_space_host_memory_allocator.h"
21 #include "host-common/address_space_shared_slots_host_memory_allocator.h"
22 #include "host-common/vm_operations.h"
23
24 #include "aemu/base/synchronization/Lock.h"
25
26 #include <map>
27 #include <unordered_map>
28 #include <memory>
29
30 using android::base::AutoLock;
31 using android::base::Lock;
32 using android::base::Stream;
33 using android::emulation::asg::AddressSpaceGraphicsContext;
34
35 using namespace android::emulation;
36
37 #define AS_DEVICE_DEBUG 0
38
39 #if AS_DEVICE_DEBUG
40 #define AS_DEVICE_DPRINT(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
41 #else
42 #define AS_DEVICE_DPRINT(fmt,...)
43 #endif
44
45 const QAndroidVmOperations* sVmOps = nullptr;
46
47 namespace {
48
49 class AddressSpaceDeviceState {
50 public:
51 AddressSpaceDeviceState() = default;
52 ~AddressSpaceDeviceState() = default;
53
genHandle()54 uint32_t genHandle() {
55 AutoLock lock(mContextsLock);
56
57 auto res = mHandleIndex;
58
59 if (!res) {
60 ++res;
61 mHandleIndex += 2;
62 } else {
63 ++mHandleIndex;
64 }
65
66 AS_DEVICE_DPRINT("new handle: %u", res);
67 return res;
68 }
69
destroyHandle(uint32_t handle)70 void destroyHandle(uint32_t handle) {
71 AS_DEVICE_DPRINT("erase handle: %u", handle);
72 AutoLock lock(mContextsLock);
73 mContexts.erase(handle);
74 }
75
tellPingInfo(uint32_t handle,uint64_t gpa)76 void tellPingInfo(uint32_t handle, uint64_t gpa) {
77 AutoLock lock(mContextsLock);
78 auto& contextDesc = mContexts[handle];
79 contextDesc.pingInfo =
80 (AddressSpaceDevicePingInfo*)
81 sVmOps->physicalMemoryGetAddr(gpa);
82 contextDesc.pingInfoGpa = gpa;
83 AS_DEVICE_DPRINT("Ping info: gpa 0x%llx @ %p\n", (unsigned long long)gpa,
84 contextDesc.pingInfo);
85 }
86
createInstance(const struct AddressSpaceCreateInfo & create)87 void createInstance(const struct AddressSpaceCreateInfo& create) {
88 AutoLock lock(mContextsLock);
89 auto& contextDesc = mContexts[create.handle];
90 contextDesc.device_context = buildAddressSpaceDeviceContext(create);
91 }
92
ping(uint32_t handle)93 void ping(uint32_t handle) {
94 AutoLock lock(mContextsLock);
95 auto& contextDesc = mContexts[handle];
96 AddressSpaceDevicePingInfo* pingInfo = contextDesc.pingInfo;
97
98 const uint64_t phys_addr = pingInfo->phys_addr;
99
100 AS_DEVICE_DPRINT(
101 "handle %u data 0x%llx -> %p size %llu meta 0x%llx\n", handle,
102 (unsigned long long)phys_addr,
103 sVmOps->physicalMemoryGetAddr(phys_addr),
104 (unsigned long long)pingInfo->size, (unsigned long long)pingInfo->metadata);
105
106 AddressSpaceDeviceContext *device_context = contextDesc.device_context.get();
107 if (device_context) {
108 device_context->perform(pingInfo);
109 } else {
110 // The first ioctl establishes the device type
111 struct AddressSpaceCreateInfo create = {0};
112 create.type = static_cast<AddressSpaceDeviceType>(pingInfo->metadata);
113 create.physAddr = phys_addr;
114
115 contextDesc.device_context = buildAddressSpaceDeviceContext(create);
116 pingInfo->metadata = contextDesc.device_context ? 0 : -1;
117 }
118 }
119
pingAtHva(uint32_t handle,AddressSpaceDevicePingInfo * pingInfo)120 void pingAtHva(uint32_t handle, AddressSpaceDevicePingInfo* pingInfo) {
121 AutoLock lock(mContextsLock);
122 auto& contextDesc = mContexts[handle];
123
124 const uint64_t phys_addr = pingInfo->phys_addr;
125
126 AS_DEVICE_DPRINT(
127 "handle %u data 0x%llx -> %p size %llu meta 0x%llx\n", handle,
128 (unsigned long long)phys_addr,
129 sVmOps->physicalMemoryGetAddr(phys_addr),
130 (unsigned long long)pingInfo->size, (unsigned long long)pingInfo->metadata);
131
132 AddressSpaceDeviceContext *device_context = contextDesc.device_context.get();
133 if (device_context) {
134 device_context->perform(pingInfo);
135 } else {
136 struct AddressSpaceCreateInfo create = {0};
137 create.type = static_cast<AddressSpaceDeviceType>(pingInfo->metadata);
138 create.physAddr = phys_addr;
139
140 contextDesc.device_context = buildAddressSpaceDeviceContext(create);
141 pingInfo->metadata = contextDesc.device_context ? 0 : -1;
142 }
143 }
144
registerDeallocationCallback(uint64_t gpa,void * context,address_space_device_deallocation_callback_t func)145 void registerDeallocationCallback(uint64_t gpa, void* context, address_space_device_deallocation_callback_t func) {
146 AutoLock lock(mContextsLock);
147 auto& currentCallbacks = mDeallocationCallbacks[gpa];
148
149 DeallocationCallbackEntry entry = {
150 context,
151 func,
152 };
153
154 currentCallbacks.push_back(entry);
155 }
156
runDeallocationCallbacks(uint64_t gpa)157 void runDeallocationCallbacks(uint64_t gpa) {
158 AutoLock lock(mContextsLock);
159
160 auto it = mDeallocationCallbacks.find(gpa);
161 if (it == mDeallocationCallbacks.end()) return;
162
163 auto& callbacks = it->second;
164
165 for (auto& entry: callbacks) {
166 entry.func(entry.context, gpa);
167 }
168
169 mDeallocationCallbacks.erase(gpa);
170 }
171
handleToContext(uint32_t handle)172 AddressSpaceDeviceContext* handleToContext(uint32_t handle) {
173 AutoLock lock(mContextsLock);
174 if (mContexts.find(handle) == mContexts.end()) return nullptr;
175
176 auto& contextDesc = mContexts[handle];
177 return contextDesc.device_context.get();
178 }
179
hostmemRegister(const struct MemEntry * entry)180 uint64_t hostmemRegister(const struct MemEntry *entry) {
181 return sVmOps->hostmemRegister(entry);
182 }
183
hostmemUnregister(uint64_t id)184 void hostmemUnregister(uint64_t id) {
185 sVmOps->hostmemUnregister(id);
186 }
187
save(Stream * stream) const188 void save(Stream* stream) const {
189 // Pre-save
190 for (const auto &kv : mContexts) {
191 const AddressSpaceContextDescription &desc = kv.second;
192 const AddressSpaceDeviceContext *device_context = desc.device_context.get();
193 if (device_context) {
194 device_context->preSave();
195 }
196 }
197
198 AddressSpaceGraphicsContext::globalStatePreSave();
199
200 // Save
201 AddressSpaceSharedSlotsHostMemoryAllocatorContext::globalStateSave(stream);
202 AddressSpaceGraphicsContext::globalStateSave(stream);
203
204 stream->putBe32(mHandleIndex);
205 stream->putBe32(mContexts.size());
206
207 for (const auto &kv : mContexts) {
208 const uint32_t handle = kv.first;
209 const AddressSpaceContextDescription &desc = kv.second;
210 const AddressSpaceDeviceContext *device_context = desc.device_context.get();
211
212 stream->putBe32(handle);
213 stream->putBe64(desc.pingInfoGpa);
214
215 if (device_context) {
216 stream->putByte(1);
217 stream->putBe32(device_context->getDeviceType());
218 device_context->save(stream);
219 } else {
220 stream->putByte(0);
221 }
222 }
223
224 // Post save
225
226 AddressSpaceGraphicsContext::globalStatePostSave();
227
228 for (const auto &kv : mContexts) {
229 const AddressSpaceContextDescription &desc = kv.second;
230 const AddressSpaceDeviceContext *device_context = desc.device_context.get();
231 if (device_context) {
232 device_context->postSave();
233 }
234 }
235 }
236
load(Stream * stream)237 bool load(Stream* stream) {
238 // First destroy all contexts, because
239 // this can be done while an emulator is running
240 clear();
241
242 if (!AddressSpaceSharedSlotsHostMemoryAllocatorContext::globalStateLoad(
243 stream,
244 get_address_space_device_control_ops(),
245 get_address_space_device_hw_funcs())) {
246 return false;
247 }
248
249 asg::AddressSpaceGraphicsContext::init(get_address_space_device_control_ops());
250
251 if (!AddressSpaceGraphicsContext::globalStateLoad(
252 stream)) {
253 return false;
254 }
255
256 const uint32_t handleIndex = stream->getBe32();
257 const size_t size = stream->getBe32();
258
259 Contexts contexts;
260 for (size_t i = 0; i < size; ++i) {
261 const uint32_t handle = stream->getBe32();
262 const uint64_t pingInfoGpa = stream->getBe64();
263
264 std::unique_ptr<AddressSpaceDeviceContext> context;
265 switch (stream->getByte()) {
266 case 0:
267 break;
268
269 case 1: {
270 struct AddressSpaceCreateInfo create = {0};
271 create.type = static_cast<AddressSpaceDeviceType>(stream->getBe32());
272 create.physAddr = pingInfoGpa;
273 create.fromSnapshot = true;
274
275 context = buildAddressSpaceDeviceContext(create);
276 if (!context || !context->load(stream)) {
277 return false;
278 }
279 }
280 break;
281
282 default:
283 return false;
284 }
285
286 auto &desc = contexts[handle];
287 desc.pingInfoGpa = pingInfoGpa;
288 if (desc.pingInfoGpa == ~0ULL) {
289 fprintf(stderr, "%s: warning: restoring hva-only ping\n", __func__);
290 } else {
291 desc.pingInfo = (AddressSpaceDevicePingInfo*)
292 sVmOps->physicalMemoryGetAddr(pingInfoGpa);
293 }
294 desc.device_context = std::move(context);
295 }
296
297 {
298 AutoLock lock(mContextsLock);
299 mHandleIndex = handleIndex;
300 mContexts = std::move(contexts);
301 }
302
303 return true;
304 }
305
clear()306 void clear() {
307 AutoLock lock(mContextsLock);
308 mContexts.clear();
309 AddressSpaceSharedSlotsHostMemoryAllocatorContext::globalStateClear();
310 auto it = mMemoryMappings.begin();
311 std::vector<std::pair<uint64_t, uint64_t>> gpasSizesToErase;
312 for (auto it: mMemoryMappings) {
313 auto gpa = it.first;
314 auto size = it.second.second;
315 gpasSizesToErase.push_back({gpa, size});
316 }
317 for (const auto& gpaSize : gpasSizesToErase) {
318 removeMemoryMappingLocked(gpaSize.first, gpaSize.second);
319 }
320 mMemoryMappings.clear();
321 }
322
addMemoryMapping(uint64_t gpa,void * ptr,uint64_t size)323 bool addMemoryMapping(uint64_t gpa, void *ptr, uint64_t size) {
324 AutoLock lock(mMemoryMappingsLock);
325 return addMemoryMappingLocked(gpa, ptr, size);
326 }
327
removeMemoryMapping(uint64_t gpa,uint64_t size)328 bool removeMemoryMapping(uint64_t gpa, uint64_t size) {
329 AutoLock lock(mMemoryMappingsLock);
330 return removeMemoryMappingLocked(gpa, size);
331 }
332
getHostPtr(uint64_t gpa) const333 void *getHostPtr(uint64_t gpa) const {
334 AutoLock lock(mMemoryMappingsLock);
335 return getHostPtrLocked(gpa);
336 }
337
338 private:
339 mutable Lock mContextsLock;
340 uint32_t mHandleIndex = 1;
341 typedef std::unordered_map<uint32_t, AddressSpaceContextDescription> Contexts;
342 Contexts mContexts;
343
buildAddressSpaceDeviceContext(const struct AddressSpaceCreateInfo & create)344 std::unique_ptr<AddressSpaceDeviceContext> buildAddressSpaceDeviceContext(
345 const struct AddressSpaceCreateInfo& create) {
346 typedef std::unique_ptr<AddressSpaceDeviceContext> DeviceContextPtr;
347
348 switch (create.type) {
349 case AddressSpaceDeviceType::Graphics:
350 asg::AddressSpaceGraphicsContext::init(get_address_space_device_control_ops());
351 return DeviceContextPtr(new asg::AddressSpaceGraphicsContext(create));
352 #ifndef AEMU_MIN
353 case AddressSpaceDeviceType::Media:
354 AS_DEVICE_DPRINT("allocating media context");
355 return DeviceContextPtr(
356 new AddressSpaceHostMediaContext(create, get_address_space_device_control_ops()));
357 #endif
358 case AddressSpaceDeviceType::Sensors:
359 return nullptr;
360 case AddressSpaceDeviceType::Power:
361 return nullptr;
362 case AddressSpaceDeviceType::GenericPipe:
363 return nullptr;
364 case AddressSpaceDeviceType::HostMemoryAllocator:
365 return DeviceContextPtr(new AddressSpaceHostMemoryAllocatorContext(
366 get_address_space_device_control_ops()));
367 case AddressSpaceDeviceType::SharedSlotsHostMemoryAllocator:
368 return DeviceContextPtr(new AddressSpaceSharedSlotsHostMemoryAllocatorContext(
369 get_address_space_device_control_ops(),
370 get_address_space_device_hw_funcs()));
371
372 case AddressSpaceDeviceType::VirtioGpuGraphics:
373 asg::AddressSpaceGraphicsContext::init(get_address_space_device_control_ops());
374 return DeviceContextPtr(new asg::AddressSpaceGraphicsContext(create));
375
376 default:
377 AS_DEVICE_DPRINT("Bad device type");
378 return nullptr;
379 }
380 }
381
addMemoryMappingLocked(uint64_t gpa,void * ptr,uint64_t size)382 bool addMemoryMappingLocked(uint64_t gpa, void *ptr, uint64_t size) {
383 if (mMemoryMappings.insert({gpa, {ptr, size}}).second) {
384 sVmOps->mapUserBackedRam(gpa, ptr, size);
385 return true;
386 } else {
387 fprintf(stderr, "%s: failed: hva %p -> gpa [0x%llx 0x%llx]\n", __func__,
388 ptr,
389 (unsigned long long)gpa,
390 (unsigned long long)size);
391 return false;
392 }
393 }
394
removeMemoryMappingLocked(uint64_t gpa,uint64_t size)395 bool removeMemoryMappingLocked(uint64_t gpa, uint64_t size) {
396 if (mMemoryMappings.erase(gpa) > 0) {
397 sVmOps->unmapUserBackedRam(gpa, size);
398 return true;
399 } else {
400 fprintf(stderr, "%s: failed: gpa [0x%llx 0x%llx]\n", __func__,
401 (unsigned long long)gpa,
402 (unsigned long long)size);
403 *(uint32_t*)(123) = 12;
404 return false;
405 }
406 }
407
getHostPtrLocked(uint64_t gpa) const408 void *getHostPtrLocked(uint64_t gpa) const {
409 auto i = mMemoryMappings.lower_bound(gpa); // i->first >= gpa (or i==end)
410 if ((i != mMemoryMappings.end()) && (i->first == gpa)) {
411 return i->second.first; // gpa is exactly the beginning of the range
412 } else if (i == mMemoryMappings.begin()) {
413 return nullptr; // can't '--i', see below
414 } else {
415 --i;
416
417 if ((i->first + i->second.second) > gpa) {
418 // move the host ptr by +(gpa-base)
419 return static_cast<char *>(i->second.first) + (gpa - i->first);
420 } else {
421 return nullptr; // the range does not cover gpa
422 }
423 }
424 }
425
426 mutable Lock mMemoryMappingsLock;
427 std::map<uint64_t, std::pair<void *, uint64_t>> mMemoryMappings; // do not save/load
428
429 struct DeallocationCallbackEntry {
430 void* context;
431 address_space_device_deallocation_callback_t func;
432 };
433
434 std::map<uint64_t, std::vector<DeallocationCallbackEntry>> mDeallocationCallbacks; // do not save/load, users re-register on load
435 };
436
sAddressSpaceDeviceState()437 static AddressSpaceDeviceState* sAddressSpaceDeviceState() {
438 static AddressSpaceDeviceState* s = new AddressSpaceDeviceState;
439 return s;
440 }
441
sAddressSpaceDeviceGenHandle()442 static uint32_t sAddressSpaceDeviceGenHandle() {
443 return sAddressSpaceDeviceState()->genHandle();
444 }
445
sAddressSpaceDeviceDestroyHandle(uint32_t handle)446 static void sAddressSpaceDeviceDestroyHandle(uint32_t handle) {
447 sAddressSpaceDeviceState()->destroyHandle(handle);
448 }
449
sAddressSpaceDeviceCreateInstance(const struct AddressSpaceCreateInfo & create)450 static void sAddressSpaceDeviceCreateInstance(const struct AddressSpaceCreateInfo& create) {
451 sAddressSpaceDeviceState()->createInstance(create);
452 }
453
sAddressSpaceDeviceTellPingInfo(uint32_t handle,uint64_t gpa)454 static void sAddressSpaceDeviceTellPingInfo(uint32_t handle, uint64_t gpa) {
455 sAddressSpaceDeviceState()->tellPingInfo(handle, gpa);
456 }
457
sAddressSpaceDevicePing(uint32_t handle)458 static void sAddressSpaceDevicePing(uint32_t handle) {
459 sAddressSpaceDeviceState()->ping(handle);
460 }
461
sAddressSpaceDeviceAddMemoryMapping(uint64_t gpa,void * ptr,uint64_t size)462 int sAddressSpaceDeviceAddMemoryMapping(uint64_t gpa, void *ptr, uint64_t size) {
463 return sAddressSpaceDeviceState()->addMemoryMapping(gpa, ptr, size) ? 1 : 0;
464 }
465
sAddressSpaceDeviceRemoveMemoryMapping(uint64_t gpa,void * ptr,uint64_t size)466 int sAddressSpaceDeviceRemoveMemoryMapping(uint64_t gpa, void *ptr, uint64_t size) {
467 (void)ptr; // TODO(lfy): remove arg
468 return sAddressSpaceDeviceState()->removeMemoryMapping(gpa, size) ? 1 : 0;
469 }
470
sAddressSpaceDeviceGetHostPtr(uint64_t gpa)471 void* sAddressSpaceDeviceGetHostPtr(uint64_t gpa) {
472 return sAddressSpaceDeviceState()->getHostPtr(gpa);
473 }
474
sAddressSpaceHandleToContext(uint32_t handle)475 static void* sAddressSpaceHandleToContext(uint32_t handle) {
476 return (void*)(sAddressSpaceDeviceState()->handleToContext(handle));
477 }
478
sAddressSpaceDeviceClear()479 static void sAddressSpaceDeviceClear() {
480 sAddressSpaceDeviceState()->clear();
481 }
482
sAddressSpaceDeviceHostmemRegister(const struct MemEntry * entry)483 static uint64_t sAddressSpaceDeviceHostmemRegister(const struct MemEntry *entry) {
484 return sAddressSpaceDeviceState()->hostmemRegister(entry);
485 }
486
sAddressSpaceDeviceHostmemUnregister(uint64_t id)487 static void sAddressSpaceDeviceHostmemUnregister(uint64_t id) {
488 sAddressSpaceDeviceState()->hostmemUnregister(id);
489 }
490
sAddressSpaceDevicePingAtHva(uint32_t handle,void * hva)491 static void sAddressSpaceDevicePingAtHva(uint32_t handle, void* hva) {
492 sAddressSpaceDeviceState()->pingAtHva(
493 handle, (AddressSpaceDevicePingInfo*)hva);
494 }
495
sAddressSpaceDeviceRegisterDeallocationCallback(void * context,uint64_t gpa,address_space_device_deallocation_callback_t func)496 static void sAddressSpaceDeviceRegisterDeallocationCallback(
497 void* context, uint64_t gpa, address_space_device_deallocation_callback_t func) {
498 sAddressSpaceDeviceState()->registerDeallocationCallback(gpa, context, func);
499 }
500
sAddressSpaceDeviceRunDeallocationCallbacks(uint64_t gpa)501 static void sAddressSpaceDeviceRunDeallocationCallbacks(uint64_t gpa) {
502 sAddressSpaceDeviceState()->runDeallocationCallbacks(gpa);
503 }
504
sAddressSpaceDeviceControlGetHwFuncs()505 static const struct AddressSpaceHwFuncs* sAddressSpaceDeviceControlGetHwFuncs() {
506 return get_address_space_device_hw_funcs();
507 }
508
509
510 } // namespace
511
512 extern "C" {
513
514 static struct address_space_device_control_ops sAddressSpaceDeviceOps = {
515 &sAddressSpaceDeviceGenHandle, // gen_handle
516 &sAddressSpaceDeviceDestroyHandle, // destroy_handle
517 &sAddressSpaceDeviceTellPingInfo, // tell_ping_info
518 &sAddressSpaceDevicePing, // ping
519 &sAddressSpaceDeviceAddMemoryMapping, // add_memory_mapping
520 &sAddressSpaceDeviceRemoveMemoryMapping, // remove_memory_mapping
521 &sAddressSpaceDeviceGetHostPtr, // get_host_ptr
522 &sAddressSpaceHandleToContext, // handle_to_context
523 &sAddressSpaceDeviceClear, // clear
524 &sAddressSpaceDeviceHostmemRegister, // hostmem register
525 &sAddressSpaceDeviceHostmemUnregister, // hostmem unregister
526 &sAddressSpaceDevicePingAtHva, // ping_at_hva
527 &sAddressSpaceDeviceRegisterDeallocationCallback, // register_deallocation_callback
528 &sAddressSpaceDeviceRunDeallocationCallbacks, // run_deallocation_callbacks
529 &sAddressSpaceDeviceControlGetHwFuncs, // control_get_hw_funcs
530 &sAddressSpaceDeviceCreateInstance, // create_instance
531 };
532
get_address_space_device_control_ops(void)533 struct address_space_device_control_ops* get_address_space_device_control_ops(void) {
534 return &sAddressSpaceDeviceOps;
535 }
536
537 static const struct AddressSpaceHwFuncs* sAddressSpaceHwFuncs = nullptr;
538
address_space_set_hw_funcs(const AddressSpaceHwFuncs * hwFuncs)539 const struct AddressSpaceHwFuncs* address_space_set_hw_funcs(
540 const AddressSpaceHwFuncs* hwFuncs) {
541 const AddressSpaceHwFuncs* result = sAddressSpaceHwFuncs;
542 sAddressSpaceHwFuncs = hwFuncs;
543 return result;
544 }
545
get_address_space_device_hw_funcs(void)546 const struct AddressSpaceHwFuncs* get_address_space_device_hw_funcs(void) {
547 return sAddressSpaceHwFuncs;
548 }
549
address_space_set_vm_operations(const QAndroidVmOperations * vmops)550 void address_space_set_vm_operations(const QAndroidVmOperations* vmops) {
551 sVmOps = vmops;
552 }
553
554 } // extern "C"
555
556 namespace android {
557 namespace emulation {
558
goldfish_address_space_set_vm_operations(const QAndroidVmOperations * vmops)559 void goldfish_address_space_set_vm_operations(const QAndroidVmOperations* vmops) {
560 sVmOps = vmops;
561 }
562
goldfish_address_space_get_vm_operations()563 const QAndroidVmOperations* goldfish_address_space_get_vm_operations() {
564 return sVmOps;
565 }
566
goldfish_address_space_memory_state_load(android::base::Stream * stream)567 int goldfish_address_space_memory_state_load(android::base::Stream *stream) {
568 return sAddressSpaceDeviceState()->load(stream) ? 0 : 1;
569 }
570
goldfish_address_space_memory_state_save(android::base::Stream * stream)571 int goldfish_address_space_memory_state_save(android::base::Stream *stream) {
572 sAddressSpaceDeviceState()->save(stream);
573 return 0;
574 }
575
576 } // namespace emulation
577 } // namespace android
578