View Javadoc
1   /*
2    * Copyright 2016-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.mac;
6   
7   import static oshi.util.Memoizer.memoize;
8   
9   import java.nio.charset.StandardCharsets;
10  import java.util.function.Supplier;
11  
12  import com.sun.jna.Native;
13  import com.sun.jna.platform.mac.IOKit.IOIterator;
14  import com.sun.jna.platform.mac.IOKit.IORegistryEntry;
15  import com.sun.jna.platform.mac.IOKitUtil;
16  
17  import oshi.annotation.concurrent.Immutable;
18  import oshi.hardware.common.AbstractFirmware;
19  import oshi.util.Constants;
20  import oshi.util.Util;
21  import oshi.util.tuples.Quintet;
22  
23  /**
24   * Firmware data obtained from ioreg.
25   */
26  @Immutable
27  final class MacFirmware extends AbstractFirmware {
28  
29      private final Supplier<Quintet<String, String, String, String, String>> manufNameDescVersRelease = memoize(
30              MacFirmware::queryEfi);
31  
32      @Override
33      public String getManufacturer() {
34          return manufNameDescVersRelease.get().getA();
35      }
36  
37      @Override
38      public String getName() {
39          return manufNameDescVersRelease.get().getB();
40      }
41  
42      @Override
43      public String getDescription() {
44          return manufNameDescVersRelease.get().getC();
45      }
46  
47      @Override
48      public String getVersion() {
49          return manufNameDescVersRelease.get().getD();
50      }
51  
52      @Override
53      public String getReleaseDate() {
54          return manufNameDescVersRelease.get().getE();
55      }
56  
57      private static Quintet<String, String, String, String, String> queryEfi() {
58          String manufacturer = null;
59          String name = null;
60          String description = null;
61          String version = null;
62          String releaseDate = null;
63  
64          IORegistryEntry platformExpert = IOKitUtil.getMatchingService("IOPlatformExpertDevice");
65          byte[] data;
66          if (platformExpert != null) {
67              IOIterator iter = platformExpert.getChildIterator("IODeviceTree");
68              if (iter != null) {
69                  IORegistryEntry entry = iter.next();
70                  while (entry != null) {
71                      switch (entry.getName()) {
72                      case "rom":
73                          data = entry.getByteArrayProperty("vendor");
74                          if (data != null) {
75                              manufacturer = Native.toString(data, StandardCharsets.UTF_8);
76                          }
77                          data = entry.getByteArrayProperty("version");
78                          if (data != null) {
79                              version = Native.toString(data, StandardCharsets.UTF_8);
80                          }
81                          data = entry.getByteArrayProperty("release-date");
82                          if (data != null) {
83                              releaseDate = Native.toString(data, StandardCharsets.UTF_8);
84                          }
85                          break;
86                      case "chosen":
87                          data = entry.getByteArrayProperty("booter-name");
88                          if (data != null) {
89                              name = Native.toString(data, StandardCharsets.UTF_8);
90                          }
91                          break;
92                      case "efi":
93                          data = entry.getByteArrayProperty("firmware-abi");
94                          if (data != null) {
95                              description = Native.toString(data, StandardCharsets.UTF_8);
96                          }
97                          break;
98                      default:
99                          if (Util.isBlank(name)) {
100                             name = entry.getStringProperty("IONameMatch");
101                         }
102                         break;
103                     }
104                     entry.release();
105                     entry = iter.next();
106                 }
107                 iter.release();
108             }
109             if (Util.isBlank(manufacturer)) {
110                 data = platformExpert.getByteArrayProperty("manufacturer");
111                 if (data != null) {
112                     manufacturer = Native.toString(data, StandardCharsets.UTF_8);
113                 }
114             }
115             if (Util.isBlank(version)) {
116                 data = platformExpert.getByteArrayProperty("target-type");
117                 if (data != null) {
118                     version = Native.toString(data, StandardCharsets.UTF_8);
119                 }
120             }
121             if (Util.isBlank(name)) {
122                 data = platformExpert.getByteArrayProperty("device_type");
123                 if (data != null) {
124                     name = Native.toString(data, StandardCharsets.UTF_8);
125                 }
126             }
127             platformExpert.release();
128         }
129         return new Quintet<>(Util.isBlank(manufacturer) ? Constants.UNKNOWN : manufacturer,
130                 Util.isBlank(name) ? Constants.UNKNOWN : name,
131                 Util.isBlank(description) ? Constants.UNKNOWN : description,
132                 Util.isBlank(version) ? Constants.UNKNOWN : version,
133                 Util.isBlank(releaseDate) ? Constants.UNKNOWN : releaseDate);
134     }
135 }