From 472c5a32948e65937f15ada4c5bfa3ed83127de3 Mon Sep 17 00:00:00 2001
From: Sergei Trofimov <sergei.trofimov@arm.com>
Date: Fri, 13 Jul 2018 12:18:17 +0100
Subject: [PATCH] target: add system_id

Add system_id attribute to targets. This ID is supposed unique for a
combination of hardware, kernel, and the file system, and contains
elements from each.

1. Hardware is identified by the concatenation of MAC addresses of
   'link/ether' network  interfaces on the system. This method is used,
   as DMI tables are often unimplemented on ARM targets.
2. The kernel is identified by its version.
3. The file system is identified by the concatenation of UUID's of the
   target's partitions. It would be more correct to only use UUID of
   the root partition, as system_id is not intended to be affected by
   removable, media, however, there is no straight-forward way of
   reliably identifying that without root.

system_id is intended to be used as an key for the purposes of caching
information about a particular device (e.g. so that it does not need to
be probed on each run).
---
 devlib/bin/scripts/shutils.in | 22 +++++++++++++++++++++-
 devlib/target.py              | 12 ++++++++++++
 doc/target.rst                |  6 ++++++
 3 files changed, 39 insertions(+), 1 deletion(-)

diff --git a/devlib/bin/scripts/shutils.in b/devlib/bin/scripts/shutils.in
index 74f2fe7..eba9d2d 100755
--- a/devlib/bin/scripts/shutils.in
+++ b/devlib/bin/scripts/shutils.in
@@ -214,7 +214,7 @@ cgroups_freezer_set_state() {
 
     # Set the state of the freezer
     echo $STATE > $SYSFS_ENTRY
-    
+
     # And check it applied cleanly
     for i in `seq 1 10`; do
         [ $($CAT $SYSFS_ENTRY) = $STATE ] && exit 0
@@ -264,6 +264,20 @@ read_tree_values() {
     fi
 }
 
+get_linux_system_id() {
+	kernel=$($BUSYBOX uname -r)
+	hardware=$($BUSYBOX ip a | $BUSYBOX grep 'link/ether' | $BUSYBOX sed 's/://g' | $BUSYBOX awk '{print $2}' | $BUSYBOX tr -d '\n')
+	filesystem=$(ls /dev/disk/by-uuid | $BUSYBOX tr '\n' '-' | $BUSYBOX sed 's/-$//')
+	echo "$hardware/$kernel/$filesystem"
+}
+
+get_android_system_id() {
+	kernel=$($BUSYBOX uname -r)
+	hardware=$($BUSYBOX ip a | $BUSYBOX grep 'link/ether' | $BUSYBOX sed 's/://g' | $BUSYBOX awk '{print $2}' | $BUSYBOX tr -d '\n')
+	filesystem=$(content query --uri content://settings/secure --projection value --where "name='android_id'" | $BUSYBOX cut -f2 -d=)
+	echo "$hardware/$kernel/$filesystem"
+}
+
 ################################################################################
 # Main Function Dispatcher
 ################################################################################
@@ -323,6 +337,12 @@ hotplug_online_all)
 read_tree_values)
 	read_tree_values $*
     ;;
+get_linux_system_id)
+	get_linux_system_id $*
+    ;;
+get_android_system_id)
+	get_android_system_id $*
+    ;;
 *)
     echo "Command [$CMD] not supported"
     exit -1
diff --git a/devlib/target.py b/devlib/target.py
index 81a76b3..3853cc0 100644
--- a/devlib/target.py
+++ b/devlib/target.py
@@ -59,6 +59,7 @@ class Target(object):
 
     path = None
     os = None
+    system_id = None
 
     default_modules = [
         'hotplug',
@@ -799,6 +800,7 @@ class Target(object):
             GOOGLE_DNS_SERVER_ADDRESS, attempts))
         return False
 
+
 class LinuxTarget(Target):
 
     path = posixpath
@@ -842,6 +844,11 @@ class LinuxTarget(Target):
             return device_model_to_return.rstrip(' \t\r\n\0')
         return None
 
+    @property
+    @memoized
+    def system_id(self):
+        return self._execute_util('get_linux_system_id').strip()
+
     def __init__(self,
                  connection_settings=None,
                  platform=None,
@@ -1020,6 +1027,11 @@ class AndroidTarget(Target):
         except KeyError:
             return None
 
+    @property
+    @memoized
+    def system_id(self):
+        return self._execute_util('get_android_system_id').strip()
+
     @property
     @memoized
     def external_storage(self):
diff --git a/doc/target.rst b/doc/target.rst
index e0a1586..369d417 100644
--- a/doc/target.rst
+++ b/doc/target.rst
@@ -120,6 +120,12 @@ Target
    This is a dict that contains a mapping of OS version elements to their
    values. This mapping is OS-specific.
 
+.. attribute:: Target.system_id
+
+   A unique identifier for the system running on the target. This identifier is
+   intended to be uninque for the combination of hardware, kernel, and file
+   system.
+
 .. attribute:: Target.cpuinfo
 
    This is a :class:`Cpuinfo` instance which contains parsed contents of