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