Linux uname() per FFI in dart/flutter einbinden
uname() unter dart zur Bestimmung der CPU Architektur per FFI einbinden.
Mit Pi OS 64 wurde das Paket system_info, das in meinem Projekt dart_periphery die CPU Archtitektur des SoC bestimmt hat, dysfunktional. system_info hat für die Bestimmung der CPU Architektur die relevanten Elemente des Device-Tree /proc/cpuinfo
ausgelesen. Im Gegensatz zur 32-Bit Version liefert aber die 64-Bit Version des Device-Trees diese benötige Information nicht mehr zurück. Abgesehen von diesem technischen Problem, hat das Paket den Status discontinued erlangt. Als Ersatz wurde daher folgender Dart-Code entwickelt, der die CPU Architektur unter Linux per Aufruf von uname()
per FFI ermittelt.
import 'dart:ffi'; // For FFI
import 'package:ffi/ffi.dart';
typedef NativeCall = int Function(Pointer);
/// Supported CPU architectures
enum CPU_ARCHITECTURE { x86, x86_64, arm, arm64, notSupported, undefinded }
final DynamicLibrary nativeAddLib = DynamicLibrary.open("libc.so.6");
NativeCall uname = nativeAddLib
.lookup)>>("uname")
.asFunction();
/// Class which holds the CPU architecture of the SoC.
/// Supported uname values provided by https://en.wikipedia.org/wiki/Uname
class CpuArch {
static CpuArch? _cpuArch;
String machine;
CPU_ARCHITECTURE cpuArch;
factory CpuArch() {
_cpuArch ??= CpuArch._internal();
return _cpuArch as CpuArch;
}
CpuArch._internal()
: machine = "",
cpuArch = CPU_ARCHITECTURE.notSupported {
Uname uname = nativeUname();
machine = uname.machine;
switch (uname.machine) {
case 'i686':
case 'i386':
cpuArch = CPU_ARCHITECTURE.x86;
break;
case 'x86_64':
cpuArch = CPU_ARCHITECTURE.x86_64;
break;
case 'aarch64':
case 'aarch64_be':
case 'arm64':
case 'armv8b':
case 'armv8l':
cpuArch = CPU_ARCHITECTURE.arm64;
break;
case 'armv':
case 'armv6l':
case 'armv7l':
cpuArch = CPU_ARCHITECTURE.arm;
break;
}
}
}
/// Uname class, container for the Linux uname struct values.
class Uname {
String sysname;
String nodename;
String release;
String version;
String machine;
Uname(this.sysname, this.nodename, this.release, this.version, this.machine);
}
/// Calls the native uname() function.
Uname nativeUname() {
// allocate a memory buffer for struct utsname - size value derived from this source
// https://man7.org/linux/man-pages/man2/uname.2.html
const len = 6 * 257; // maxium size
const enumElements = 5;
Pointer data = calloc(len);
try {
if (uname(data) != 0) {
throw Exception('Calling uname() failed.');
}
// calculate _UTSNAME_LENGTH
var utslen = 0;
label:
for (int i = 0; i < len; ++i) {
if (data[i] == 0) {
for (int j = i + 1; j < len; ++j) {
if (data[j] != 0) {
utslen = j;
break label;
}
}
}
}
var values = [];
// extract these 5 strings from the memory
//
// char sysname[]; /* Operating system name (e.g., "Linux") */
// char nodename[]; /* Name within "some implementation-defined network" */
// char release[]; /* Operating system release (e.g., "2.6.28") */
// char version[]; /* Operating system version */
// char machine[]; /* Hardware identifier */
for (int i = 0; i < enumElements; ++i) {
var start = utslen * i;
StringBuffer buf = StringBuffer();
for (int i = start; i < len; ++i) {
if (data[i] == 0) {
break;
}
buf.write(String.fromCharCode(data[i]));
}
values.add(buf.toString());
}
return Uname(values[0], values[1], values[2], values[3], values[4]);
} finally {
malloc.free(data);
}
}