1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.system.virtualmachine;
18 
19 import android.annotation.Nullable;
20 import android.os.PersistableBundle;
21 
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Optional;
25 
26 /** @hide */
27 public class VirtualMachineCustomImageConfig {
28     private static final String KEY_NAME = "name";
29     private static final String KEY_KERNEL = "kernel";
30     private static final String KEY_INITRD = "initrd";
31     private static final String KEY_BOOTLOADER = "bootloader";
32     private static final String KEY_PARAMS = "params";
33     private static final String KEY_DISK_WRITABLES = "disk_writables";
34     private static final String KEY_DISK_IMAGES = "disk_images";
35     private static final String KEY_DISPLAY_CONFIG = "display_config";
36     private static final String KEY_TOUCH = "touch";
37     private static final String KEY_KEYBOARD = "keyboard";
38     private static final String KEY_MOUSE = "mouse";
39     private static final String KEY_GPU = "gpu";
40 
41     @Nullable private final String name;
42     @Nullable private final String kernelPath;
43     @Nullable private final String initrdPath;
44     @Nullable private final String bootloaderPath;
45     @Nullable private final String[] params;
46     @Nullable private final Disk[] disks;
47     @Nullable private final DisplayConfig displayConfig;
48     private final boolean touch;
49     private final boolean keyboard;
50     private final boolean mouse;
51     @Nullable private final GpuConfig gpuConfig;
52 
53     @Nullable
getDisks()54     public Disk[] getDisks() {
55         return disks;
56     }
57 
58     @Nullable
getBootloaderPath()59     public String getBootloaderPath() {
60         return bootloaderPath;
61     }
62 
63     @Nullable
getInitrdPath()64     public String getInitrdPath() {
65         return initrdPath;
66     }
67 
68     @Nullable
getKernelPath()69     public String getKernelPath() {
70         return kernelPath;
71     }
72 
73     @Nullable
getName()74     public String getName() {
75         return name;
76     }
77 
78     @Nullable
getParams()79     public String[] getParams() {
80         return params;
81     }
82 
useTouch()83     public boolean useTouch() {
84         return touch;
85     }
86 
useKeyboard()87     public boolean useKeyboard() {
88         return keyboard;
89     }
90 
useMouse()91     public boolean useMouse() {
92         return mouse;
93     }
94 
95     /** @hide */
VirtualMachineCustomImageConfig( String name, String kernelPath, String initrdPath, String bootloaderPath, String[] params, Disk[] disks, DisplayConfig displayConfig, boolean touch, boolean keyboard, boolean mouse, GpuConfig gpuConfig)96     public VirtualMachineCustomImageConfig(
97             String name,
98             String kernelPath,
99             String initrdPath,
100             String bootloaderPath,
101             String[] params,
102             Disk[] disks,
103             DisplayConfig displayConfig,
104             boolean touch,
105             boolean keyboard,
106             boolean mouse,
107             GpuConfig gpuConfig) {
108         this.name = name;
109         this.kernelPath = kernelPath;
110         this.initrdPath = initrdPath;
111         this.bootloaderPath = bootloaderPath;
112         this.params = params;
113         this.disks = disks;
114         this.displayConfig = displayConfig;
115         this.touch = touch;
116         this.keyboard = keyboard;
117         this.mouse = mouse;
118         this.gpuConfig = gpuConfig;
119     }
120 
from(PersistableBundle customImageConfigBundle)121     static VirtualMachineCustomImageConfig from(PersistableBundle customImageConfigBundle) {
122         Builder builder = new Builder();
123         builder.setName(customImageConfigBundle.getString(KEY_NAME));
124         builder.setKernelPath(customImageConfigBundle.getString(KEY_KERNEL));
125         builder.setInitrdPath(customImageConfigBundle.getString(KEY_INITRD));
126         builder.setBootloaderPath(customImageConfigBundle.getString(KEY_BOOTLOADER));
127         String[] params = customImageConfigBundle.getStringArray(KEY_PARAMS);
128         if (params != null) {
129             for (String param : params) {
130                 builder.addParam(param);
131             }
132         }
133         boolean[] writables = customImageConfigBundle.getBooleanArray(KEY_DISK_WRITABLES);
134         String[] diskImages = customImageConfigBundle.getStringArray(KEY_DISK_IMAGES);
135         if (writables != null && diskImages != null) {
136             if (writables.length == diskImages.length) {
137                 for (int i = 0; i < writables.length; i++) {
138                     builder.addDisk(
139                             writables[i] ? Disk.RWDisk(diskImages[i]) : Disk.RODisk(diskImages[i]));
140                 }
141             }
142         }
143         PersistableBundle displayConfigPb =
144                 customImageConfigBundle.getPersistableBundle(KEY_DISPLAY_CONFIG);
145         builder.setDisplayConfig(DisplayConfig.from(displayConfigPb));
146         builder.useTouch(customImageConfigBundle.getBoolean(KEY_TOUCH));
147         builder.useKeyboard(customImageConfigBundle.getBoolean(KEY_KEYBOARD));
148         builder.useMouse(customImageConfigBundle.getBoolean(KEY_MOUSE));
149         builder.setGpuConfig(GpuConfig.from(customImageConfigBundle.getPersistableBundle(KEY_GPU)));
150         return builder.build();
151     }
152 
153 
154 
toPersistableBundle()155     PersistableBundle toPersistableBundle() {
156         PersistableBundle pb = new PersistableBundle();
157         pb.putString(KEY_NAME, this.name);
158         pb.putString(KEY_KERNEL, this.kernelPath);
159         pb.putString(KEY_BOOTLOADER, this.bootloaderPath);
160         pb.putString(KEY_INITRD, this.initrdPath);
161         pb.putStringArray(KEY_PARAMS, this.params);
162 
163         if (disks != null) {
164             boolean[] writables = new boolean[disks.length];
165             String[] images = new String[disks.length];
166             for (int i = 0; i < disks.length; i++) {
167                 writables[i] = disks[i].writable;
168                 images[i] = disks[i].imagePath;
169             }
170             pb.putBooleanArray(KEY_DISK_WRITABLES, writables);
171             pb.putStringArray(KEY_DISK_IMAGES, images);
172         }
173         pb.putPersistableBundle(
174                 KEY_DISPLAY_CONFIG,
175                 Optional.ofNullable(displayConfig)
176                         .map(dc -> dc.toPersistableBundle())
177                         .orElse(null));
178         pb.putBoolean(KEY_TOUCH, touch);
179         pb.putBoolean(KEY_KEYBOARD, keyboard);
180         pb.putBoolean(KEY_MOUSE, mouse);
181         pb.putPersistableBundle(
182                 KEY_GPU,
183                 Optional.ofNullable(gpuConfig).map(gc -> gc.toPersistableBundle()).orElse(null));
184         return pb;
185     }
186 
187     @Nullable
getDisplayConfig()188     public DisplayConfig getDisplayConfig() {
189         return displayConfig;
190     }
191 
192     @Nullable
getGpuConfig()193     public GpuConfig getGpuConfig() {
194         return gpuConfig;
195     }
196 
197     /** @hide */
198     public static final class Disk {
199         private final boolean writable;
200         private final String imagePath;
201 
Disk(boolean writable, String imagePath)202         private Disk(boolean writable, String imagePath) {
203             this.writable = writable;
204             this.imagePath = imagePath;
205         }
206 
207         /** @hide */
RWDisk(String imagePath)208         public static Disk RWDisk(String imagePath) {
209             return new Disk(true, imagePath);
210         }
211 
212         /** @hide */
RODisk(String imagePath)213         public static Disk RODisk(String imagePath) {
214             return new Disk(false, imagePath);
215         }
216 
217         /** @hide */
isWritable()218         public boolean isWritable() {
219             return writable;
220         }
221 
222         /** @hide */
getImagePath()223         public String getImagePath() {
224             return imagePath;
225         }
226     }
227 
228     /** @hide */
229     public static final class Builder {
230         private String name;
231         private String kernelPath;
232         private String initrdPath;
233         private String bootloaderPath;
234         private List<String> params = new ArrayList<>();
235         private List<Disk> disks = new ArrayList<>();
236         private DisplayConfig displayConfig;
237         private boolean touch;
238         private boolean keyboard;
239         private boolean mouse;
240         private GpuConfig gpuConfig;
241 
242         /** @hide */
Builder()243         public Builder() {}
244 
245         /** @hide */
setName(String name)246         public Builder setName(String name) {
247             this.name = name;
248             return this;
249         }
250 
251         /** @hide */
setKernelPath(String kernelPath)252         public Builder setKernelPath(String kernelPath) {
253             this.kernelPath = kernelPath;
254             return this;
255         }
256 
257         /** @hide */
setBootloaderPath(String bootloaderPath)258         public Builder setBootloaderPath(String bootloaderPath) {
259             this.bootloaderPath = bootloaderPath;
260             return this;
261         }
262 
263         /** @hide */
setInitrdPath(String initrdPath)264         public Builder setInitrdPath(String initrdPath) {
265             this.initrdPath = initrdPath;
266             return this;
267         }
268 
269         /** @hide */
addDisk(Disk disk)270         public Builder addDisk(Disk disk) {
271             this.disks.add(disk);
272             return this;
273         }
274 
275         /** @hide */
addParam(String param)276         public Builder addParam(String param) {
277             this.params.add(param);
278             return this;
279         }
280 
281         /** @hide */
setDisplayConfig(DisplayConfig displayConfig)282         public Builder setDisplayConfig(DisplayConfig displayConfig) {
283             this.displayConfig = displayConfig;
284             return this;
285         }
286 
287         /** @hide */
setGpuConfig(GpuConfig gpuConfig)288         public Builder setGpuConfig(GpuConfig gpuConfig) {
289             this.gpuConfig = gpuConfig;
290             return this;
291         }
292 
293         /** @hide */
useTouch(boolean touch)294         public Builder useTouch(boolean touch) {
295             this.touch = touch;
296             return this;
297         }
298 
299         /** @hide */
useKeyboard(boolean keyboard)300         public Builder useKeyboard(boolean keyboard) {
301             this.keyboard = keyboard;
302             return this;
303         }
304 
305         /** @hide */
useMouse(boolean mouse)306         public Builder useMouse(boolean mouse) {
307             this.mouse = mouse;
308             return this;
309         }
310 
311         /** @hide */
build()312         public VirtualMachineCustomImageConfig build() {
313             return new VirtualMachineCustomImageConfig(
314                     this.name,
315                     this.kernelPath,
316                     this.initrdPath,
317                     this.bootloaderPath,
318                     this.params.toArray(new String[0]),
319                     this.disks.toArray(new Disk[0]),
320                     displayConfig,
321                     touch,
322                     keyboard,
323                     mouse,
324                     gpuConfig);
325         }
326     }
327 
328     /** @hide */
329     public static final class DisplayConfig {
330         private static final String KEY_WIDTH = "width";
331         private static final String KEY_HEIGHT = "height";
332         private static final String KEY_HORIZONTAL_DPI = "horizontal_dpi";
333         private static final String KEY_VERTICAL_DPI = "vertical_dpi";
334         private static final String KEY_REFRESH_RATE = "refresh_rate";
335         private final int width;
336         private final int height;
337         private final int horizontalDpi;
338         private final int verticalDpi;
339         private final int refreshRate;
340 
DisplayConfig( int width, int height, int horizontalDpi, int verticalDpi, int refreshRate)341         private DisplayConfig(
342                 int width, int height, int horizontalDpi, int verticalDpi, int refreshRate) {
343             this.width = width;
344             this.height = height;
345             this.horizontalDpi = horizontalDpi;
346             this.verticalDpi = verticalDpi;
347             this.refreshRate = refreshRate;
348         }
349 
350         /** @hide */
getWidth()351         public int getWidth() {
352             return width;
353         }
354 
355         /** @hide */
getHeight()356         public int getHeight() {
357             return height;
358         }
359 
360         /** @hide */
getHorizontalDpi()361         public int getHorizontalDpi() {
362             return horizontalDpi;
363         }
364 
365         /** @hide */
getVerticalDpi()366         public int getVerticalDpi() {
367             return verticalDpi;
368         }
369 
370         /** @hide */
getRefreshRate()371         public int getRefreshRate() {
372             return refreshRate;
373         }
374 
toParcelable()375         android.system.virtualizationservice.DisplayConfig toParcelable() {
376             android.system.virtualizationservice.DisplayConfig parcelable =
377                     new android.system.virtualizationservice.DisplayConfig();
378             parcelable.width = this.width;
379             parcelable.height = this.height;
380             parcelable.horizontalDpi = this.horizontalDpi;
381             parcelable.verticalDpi = this.verticalDpi;
382             parcelable.refreshRate = this.refreshRate;
383 
384             return parcelable;
385         }
386 
from(PersistableBundle pb)387         private static DisplayConfig from(PersistableBundle pb) {
388             if (pb == null) {
389                 return null;
390             }
391             Builder builder = new Builder();
392             builder.setWidth(pb.getInt(KEY_WIDTH));
393             builder.setHeight(pb.getInt(KEY_HEIGHT));
394             builder.setHorizontalDpi(pb.getInt(KEY_HORIZONTAL_DPI));
395             builder.setVerticalDpi(pb.getInt(KEY_VERTICAL_DPI));
396             builder.setRefreshRate(pb.getInt(KEY_REFRESH_RATE));
397             return builder.build();
398         }
399 
toPersistableBundle()400         private PersistableBundle toPersistableBundle() {
401             PersistableBundle pb = new PersistableBundle();
402             pb.putInt(KEY_WIDTH, this.width);
403             pb.putInt(KEY_HEIGHT, this.height);
404             pb.putInt(KEY_HORIZONTAL_DPI, this.horizontalDpi);
405             pb.putInt(KEY_VERTICAL_DPI, this.verticalDpi);
406             pb.putInt(KEY_REFRESH_RATE, this.refreshRate);
407             return pb;
408         }
409 
410         /** @hide */
411         public static class Builder {
412             // Default values come from external/crosvm/vm_control/src/gpu.rs
413             private int width;
414             private int height;
415             private int horizontalDpi = 320;
416             private int verticalDpi = 320;
417             private int refreshRate = 60;
418 
419             /** @hide */
Builder()420             public Builder() {}
421 
422             /** @hide */
setWidth(int width)423             public Builder setWidth(int width) {
424                 this.width = width;
425                 return this;
426             }
427 
428             /** @hide */
setHeight(int height)429             public Builder setHeight(int height) {
430                 this.height = height;
431                 return this;
432             }
433 
434             /** @hide */
setHorizontalDpi(int horizontalDpi)435             public Builder setHorizontalDpi(int horizontalDpi) {
436                 this.horizontalDpi = horizontalDpi;
437                 return this;
438             }
439 
440             /** @hide */
setVerticalDpi(int verticalDpi)441             public Builder setVerticalDpi(int verticalDpi) {
442                 this.verticalDpi = verticalDpi;
443                 return this;
444             }
445 
446             /** @hide */
setRefreshRate(int refreshRate)447             public Builder setRefreshRate(int refreshRate) {
448                 this.refreshRate = refreshRate;
449                 return this;
450             }
451 
452             /** @hide */
build()453             public DisplayConfig build() {
454                 if (this.width == 0 || this.height == 0) {
455                     throw new IllegalStateException("width and height must be specified");
456                 }
457                 return new DisplayConfig(width, height, horizontalDpi, verticalDpi, refreshRate);
458             }
459         }
460     }
461 
462     /** @hide */
463     public static final class GpuConfig {
464         private static final String KEY_BACKEND = "backend";
465         private static final String KEY_CONTEXT_TYPES = "context_types";
466         private static final String KEY_PCI_ADDRESS = "pci_address";
467         private static final String KEY_RENDERER_FEATURES = "renderer_features";
468         private static final String KEY_RENDERER_USE_EGL = "renderer_use_egl";
469         private static final String KEY_RENDERER_USE_GLES = "renderer_use_gles";
470         private static final String KEY_RENDERER_USE_GLX = "renderer_use_glx";
471         private static final String KEY_RENDERER_USE_SURFACELESS = "renderer_use_surfaceless";
472         private static final String KEY_RENDERER_USE_VULKAN = "renderer_use_vulkan";
473 
474         private final String backend;
475         private final String[] contextTypes;
476         private final String pciAddress;
477         private final String rendererFeatures;
478         private final boolean rendererUseEgl;
479         private final boolean rendererUseGles;
480         private final boolean rendererUseGlx;
481         private final boolean rendererUseSurfaceless;
482         private final boolean rendererUseVulkan;
483 
GpuConfig( String backend, String[] contextTypes, String pciAddress, String rendererFeatures, boolean rendererUseEgl, boolean rendererUseGles, boolean rendererUseGlx, boolean rendererUseSurfaceless, boolean rendererUseVulkan)484         private GpuConfig(
485                 String backend,
486                 String[] contextTypes,
487                 String pciAddress,
488                 String rendererFeatures,
489                 boolean rendererUseEgl,
490                 boolean rendererUseGles,
491                 boolean rendererUseGlx,
492                 boolean rendererUseSurfaceless,
493                 boolean rendererUseVulkan) {
494             this.backend = backend;
495             this.contextTypes = contextTypes;
496             this.pciAddress = pciAddress;
497             this.rendererFeatures = rendererFeatures;
498             this.rendererUseEgl = rendererUseEgl;
499             this.rendererUseGles = rendererUseGles;
500             this.rendererUseGlx = rendererUseGlx;
501             this.rendererUseSurfaceless = rendererUseSurfaceless;
502             this.rendererUseVulkan = rendererUseVulkan;
503         }
504 
505         /** @hide */
getBackend()506         public String getBackend() {
507             return backend;
508         }
509 
510         /** @hide */
getContextTypes()511         public String[] getContextTypes() {
512             return contextTypes;
513         }
514 
515         /** @hide */
getPciAddress()516         public String getPciAddress() {
517             return pciAddress;
518         }
519 
520         /** @hide */
getRendererFeatures()521         public String getRendererFeatures() {
522             return rendererFeatures;
523         }
524 
525         /** @hide */
getRendererUseEgl()526         public boolean getRendererUseEgl() {
527             return rendererUseEgl;
528         }
529 
530         /** @hide */
getRendererUseGles()531         public boolean getRendererUseGles() {
532             return rendererUseGles;
533         }
534 
535         /** @hide */
getRendererUseGlx()536         public boolean getRendererUseGlx() {
537             return rendererUseGlx;
538         }
539 
540         /** @hide */
getRendererUseSurfaceless()541         public boolean getRendererUseSurfaceless() {
542             return rendererUseSurfaceless;
543         }
544 
545         /** @hide */
getRendererUseVulkan()546         public boolean getRendererUseVulkan() {
547             return rendererUseVulkan;
548         }
549 
toParcelable()550         android.system.virtualizationservice.GpuConfig toParcelable() {
551             android.system.virtualizationservice.GpuConfig parcelable =
552                     new android.system.virtualizationservice.GpuConfig();
553             parcelable.backend = this.backend;
554             parcelable.contextTypes = this.contextTypes;
555             parcelable.pciAddress = this.pciAddress;
556             parcelable.rendererFeatures = this.rendererFeatures;
557             parcelable.rendererUseEgl = this.rendererUseEgl;
558             parcelable.rendererUseGles = this.rendererUseGles;
559             parcelable.rendererUseGlx = this.rendererUseGlx;
560             parcelable.rendererUseSurfaceless = this.rendererUseSurfaceless;
561             parcelable.rendererUseVulkan = this.rendererUseVulkan;
562             return parcelable;
563         }
564 
from(PersistableBundle pb)565         private static GpuConfig from(PersistableBundle pb) {
566             if (pb == null) {
567                 return null;
568             }
569             Builder builder = new Builder();
570             builder.setBackend(pb.getString(KEY_BACKEND));
571             builder.setContextTypes(pb.getStringArray(KEY_CONTEXT_TYPES));
572             builder.setPciAddress(pb.getString(KEY_PCI_ADDRESS));
573             builder.setRendererFeatures(pb.getString(KEY_RENDERER_FEATURES));
574             builder.setRendererUseEgl(pb.getBoolean(KEY_RENDERER_USE_EGL));
575             builder.setRendererUseGles(pb.getBoolean(KEY_RENDERER_USE_GLES));
576             builder.setRendererUseGlx(pb.getBoolean(KEY_RENDERER_USE_GLX));
577             builder.setRendererUseSurfaceless(pb.getBoolean(KEY_RENDERER_USE_SURFACELESS));
578             builder.setRendererUseVulkan(pb.getBoolean(KEY_RENDERER_USE_VULKAN));
579             return builder.build();
580         }
581 
toPersistableBundle()582         private PersistableBundle toPersistableBundle() {
583             PersistableBundle pb = new PersistableBundle();
584             pb.putString(KEY_BACKEND, this.backend);
585             pb.putStringArray(KEY_CONTEXT_TYPES, this.contextTypes);
586             pb.putString(KEY_PCI_ADDRESS, this.pciAddress);
587             pb.putString(KEY_RENDERER_FEATURES, this.rendererFeatures);
588             pb.putBoolean(KEY_RENDERER_USE_EGL, this.rendererUseEgl);
589             pb.putBoolean(KEY_RENDERER_USE_GLES, this.rendererUseGles);
590             pb.putBoolean(KEY_RENDERER_USE_GLX, this.rendererUseGlx);
591             pb.putBoolean(KEY_RENDERER_USE_SURFACELESS, this.rendererUseSurfaceless);
592             pb.putBoolean(KEY_RENDERER_USE_VULKAN, this.rendererUseVulkan);
593             return pb;
594         }
595 
596         /** @hide */
597         public static class Builder {
598             private String backend;
599             private String[] contextTypes;
600             private String pciAddress;
601             private String rendererFeatures;
602             private boolean rendererUseEgl = true;
603             private boolean rendererUseGles = true;
604             private boolean rendererUseGlx = false;
605             private boolean rendererUseSurfaceless = true;
606             private boolean rendererUseVulkan = false;
607 
608             /** @hide */
Builder()609             public Builder() {}
610 
611             /** @hide */
setBackend(String backend)612             public Builder setBackend(String backend) {
613                 this.backend = backend;
614                 return this;
615             }
616 
617             /** @hide */
setContextTypes(String[] contextTypes)618             public Builder setContextTypes(String[] contextTypes) {
619                 this.contextTypes = contextTypes;
620                 return this;
621             }
622 
623             /** @hide */
setPciAddress(String pciAddress)624             public Builder setPciAddress(String pciAddress) {
625                 this.pciAddress = pciAddress;
626                 return this;
627             }
628 
629             /** @hide */
setRendererFeatures(String rendererFeatures)630             public Builder setRendererFeatures(String rendererFeatures) {
631                 this.rendererFeatures = rendererFeatures;
632                 return this;
633             }
634 
635             /** @hide */
setRendererUseEgl(Boolean rendererUseEgl)636             public Builder setRendererUseEgl(Boolean rendererUseEgl) {
637                 this.rendererUseEgl = rendererUseEgl;
638                 return this;
639             }
640 
641             /** @hide */
setRendererUseGles(Boolean rendererUseGles)642             public Builder setRendererUseGles(Boolean rendererUseGles) {
643                 this.rendererUseGles = rendererUseGles;
644                 return this;
645             }
646 
647             /** @hide */
setRendererUseGlx(Boolean rendererUseGlx)648             public Builder setRendererUseGlx(Boolean rendererUseGlx) {
649                 this.rendererUseGlx = rendererUseGlx;
650                 return this;
651             }
652 
653             /** @hide */
setRendererUseSurfaceless(Boolean rendererUseSurfaceless)654             public Builder setRendererUseSurfaceless(Boolean rendererUseSurfaceless) {
655                 this.rendererUseSurfaceless = rendererUseSurfaceless;
656                 return this;
657             }
658 
659             /** @hide */
setRendererUseVulkan(Boolean rendererUseVulkan)660             public Builder setRendererUseVulkan(Boolean rendererUseVulkan) {
661                 this.rendererUseVulkan = rendererUseVulkan;
662                 return this;
663             }
664 
665             /** @hide */
build()666             public GpuConfig build() {
667                 return new GpuConfig(
668                         backend,
669                         contextTypes,
670                         pciAddress,
671                         rendererFeatures,
672                         rendererUseEgl,
673                         rendererUseGles,
674                         rendererUseGlx,
675                         rendererUseSurfaceless,
676                         rendererUseVulkan);
677             }
678         }
679     }
680 }
681