Android Foundation: how to determine the unique identification code of Android device

This is a reprint of the article, the original link is as follows. In case of infringement, delete after contact.
link

The unique identification must satisfy two characteristics to solve the problem of locating the unique equipment perfectly, but the solution to this problem is doomed to be close to perfection

Uniqueness: the identity must be unique on all devices using the app
 Immutability: identity must remain the same on the same device

Direction 1: use hardware identification

In fact, hardware identification is required to meet these two characteristics at the time of hardware production (there is still uncertainty of manual production), but the acquisition of identification tends to be difficult, which makes the scope of the scheme using hardware identification as the unique identification code narrower and narrower, and cannot be used as a global scheme.

  1. Use device? ID
    TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
    String deviceId = tm.getDeviceId();
  2. Use Android? ID
    String androidId = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
  3. Using MAC ADDRESS

Get the Mac address of Bluetooth or wifi as the unique identification number
wifiManager = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE));
String macAddress = wifiManager.getConnectionInfo().getMacAddress();
4. Use SERIAL NUMBER

Obtained through android.os.Build.SERIAL
5. Advantages and limitations of hardware identification

Advantages: almost perfect satisfaction of uniqueness and invariance

Inferiority:
Hardware identification limitations
Device? ID - for Android 9 and below devices, you need to apply for the manifest.permission.read? Phone? State permission

  • Non mobile devices cannot be used: if only devices with Wifi or music player do not have the hardware function of calling, there is no such device? ID
  • bug: on a few mobile devices, the implementation is vulnerable and will return garbage, such as products of zeros or asterisks
  • On Android 10 devices, even if permission is granted, an error will be reported. Process: com.sj.d_ "adaptive version, PID: 8768 java.lang.securityexception: getuniquedeviceid: the user 10285 does not meet the requirements to access device identifiers
    Android UU ID - the Bug of the vendor customized system: different devices may generate the same Android UU ID: 9774d56d682e549c; some devices return null values;
    Adaptation limitations (basically not considered): the version of Android < = 2.1 or Android > = 2.3 is reliable and stable, but the version of 2.2 is not 100% reliable
    Device difference (not considered): for CDMA devices, Android? ID and TelephonyManager.getDeviceId() return the same value
    MAC ADDRESS - hardware limitations: not all devices have WiFi and Bluetooth hardware
  • Access restrictions: if WiFi is not turned on, you cannot access its Mac address; while Bluetooth can only access its Mac address when it is turned on
  • In Android 6.0 (API level 23) to Android 9 (API level 28), Mac addresses of local devices such as Wi Fi and Bluetooth cannot be used through third-party APIs. The WiFi. Getmacaddress() method and the Bluetooth adapter. Getdefaultadapter(). Getaddress() method both return 02:00:00:00:00:00.
    SERIAL NUMBER often returns Unknown
    Use UUID for direction 2

This is also the only identification code generation method recommended by the government. When there is a difference, the UUID generated in the official scheme (here) will be stored in the internal storage of the application, and the unloading and reinstallation of the APP will lead to changes. In actual use, we can store it in the external storage, unless it is deleted or damaged artificially, so its invariance is guaranteed, and its uniqueness is unique Sex is guaranteed by UUID.

Brief analysis of the implementation principle of UUID:
Wiki explanation: universal unique identifier (UUID) is a 128 bit identifier used in the computer system to identify the number of information, and related terms: global unique identifier (GUID). The UUID is generated according to the standard method and does not depend on the registration and distribution of the central authority. It is unique, which is different from most other Numbering schemes. The probability of repeated UUID code is close to zero, which can be ignored

Composition: 8-4-4-4-12 xxxxxxx-xxxx-xxxx-xxxx-nxxx-xxxxxxx M represents UUID version, one to three most significant bits of number N represent UUID variant

According to different versions, UUID s depend on different components,

The time-based UUID version is obtained by calculating the current timestamp, random number, and machine MAC address. The core algorithm of UUID ensures that the repeatability of UUID generated by multiprocessors at the same time is 0, because their time and space (node: usually MAC address) must be inconsistent.

Due to the MAC address used in the algorithm, this version of UUID can guarantee the uniqueness in the world. But at the same time, using MAC address will bring security problems, which is the criticism of this version of UUID. If the application is only used in the local area network, it can also use the degenerate algorithm to replace the MAC address with the IP address - Java UUID is often implemented in this way (of course, the difficulty of obtaining MAC is also considered).

String uniqueID = UUID.randomUUID().toString();
Perfect solution

Get the hardware ID as much as possible to meet the two characteristics. Under the conditions of restrictions or other factors, try to meet the invariance. Store the UUID in the external environment for reading and writing.

Scheme idea
 Get hardware identification as much as possible
 The hardware ID is empty for UUID generation and storage

Scheme Description:

    You need to obtain the device information permission before using (no device ID is not desirable, but it is still available), and external storage read-write permission (required, otherwise unavailable)
    It's better to use it in the Application. The unique identification is often used in the direct interaction between the app and the server. It's easy to manage and use it in a globally unified place

Another solution is to get some unique information of the device and generate a specific UUID, so that the storage can be skipped if it remains unchanged. But since you get the unique information, why generate a UUID?
public class UniqueIDUtils {

    private static final String TAG = "UniqueIDUtils";
    private static String uniqueID;
    private static String uniqueKey = "unique_id";
    private static String uniqueIDDirPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).getAbsolutePath();
    private static String uniqueIDFile = "unique.txt";


    public static String getUniqueID(Context context) {
        //Three steps to read: in memory, in the SP table of storage, in the external storage file
        if (!TextUtils.isEmpty(uniqueID)) {
            Log.e(TAG, "getUniqueID: Get in memory" + uniqueID);
            return uniqueID;
        }
        uniqueID = PreferenceManager.getDefaultSharedPreferences(context).getString(uniqueKey, "");
        if (!TextUtils.isEmpty(uniqueID)) {
            Log.e(TAG, "getUniqueID: SP Get in" + uniqueID);
            return uniqueID;
        }
        readUniqueFile(context);
        if (!TextUtils.isEmpty(uniqueID)) {
            Log.e(TAG, "getUniqueID: Get in external storage" + uniqueID);
            return uniqueID;
        }
        //Two step creation: hardware acquisition; self generation and storage
        getDeviceID(context);
        getAndroidID(context);
        getSNID();
        createUniqueID(context);
        PreferenceManager.getDefaultSharedPreferences(context).edit().putString(uniqueKey, uniqueID);
        return uniqueID;
    }

    @SuppressLint("MissingPermission")
    private static void getDeviceID(Context context) {
        if (!TextUtils.isEmpty(uniqueID)) {
            return;
        }
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
            return;
        }
        String deviceId = null;
        try {
            deviceId = ((TelephonyManager) context.getSystemService(TELEPHONY_SERVICE)).getDeviceId();
            if (TextUtils.isEmpty(deviceId)) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        uniqueID = deviceId;
        Log.e(TAG, "getUniqueID: DeviceId Get success" + uniqueID);
    }

    private static void getAndroidID(Context context) {
        if (!TextUtils.isEmpty(uniqueID)) {
            return;
        }
        String androidID = null;
        try {
            androidID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            if (TextUtils.isEmpty(androidID) || "9774d56d682e549c".equals(androidID)) {
                return;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
        uniqueID = androidID;
        Log.e(TAG, "getUniqueID: AndroidID Get success" + uniqueID);
    }

    private static void getSNID() {
        if (!TextUtils.isEmpty(uniqueID)) {
            return;
        }
        String snID = Build.SERIAL;
        if (TextUtils.isEmpty(snID)) {
            return;
        }
        uniqueID = snID;
        Log.e(TAG, "getUniqueID: SNID Get success" + uniqueID);
    }


    private static void createUniqueID(Context context) {
        if (!TextUtils.isEmpty(uniqueID)) {
            return;
        }
        uniqueID = UUID.randomUUID().toString();
        Log.e(TAG, "getUniqueID: UUID Generate success" + uniqueID);
        File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
        if (!filesDir.exists()) {
            filesDir.mkdir();
        }
        File file = new File(filesDir, uniqueIDFile);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        FileOutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(file);
            outputStream.write(uniqueID.getBytes());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void readUniqueFile(Context context) {
        File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
        File file = new File(filesDir, uniqueIDFile);
        if (file.exists()) {
            FileInputStream inputStream = null;
            try {
                inputStream = new FileInputStream(file);
                byte[] bytes = new byte[(int) file.length()];
                inputStream.read(bytes);
                uniqueID = new String(bytes);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void clearUniqueFile(Context context) {
        File filesDir = new File(uniqueIDDirPath + File.separator + context.getApplicationContext().getPackageName());
        deleteFile(filesDir);
    }

    private static void deleteFile(File file) {
        if (file.isDirectory()) {
            for (File listFile : file.listFiles()) {
                deleteFile(listFile);
            }
        } else {
            file.delete();
        }
    }
}

A perfect plan of hope but contradiction

Since the hardware ID is closed to the acquirer, the ID generated based on the hardware ID (similar to UUID) will be exposed to the acquirer. However, the control of device privacy on Android 10 makes it clear that Google does not want the app to be able to locate the same device for a long time. But what if it is generated based on the hardware ID and app package name?
Noun interpretation
Equipment code abbreviation (full name) definition
IMEI(International Mobile Equipment Identity) international mobile phone device identification code: an "electronic serial number" composed of 15 digits, which corresponds to each mobile phone one by one, and the code is the only one in the world
UUID (universal unique identifier): refers to the number generated on a machine, which ensures that it is unique to all machines in the same time and space. It is composed of the following parts: current date and time (the first part of UUID is related to time. If you generate a UUID after a few seconds, the first part is different , the rest are the same), clock sequence, and globally unique IEEE machine identification number (if there is a network card, it is obtained from the network card, and no network card is obtained in other ways)
MEID (Mobile Equipment IDentifier) is the only 56bit CDMA mobile terminal identification number in the world. The ID number will be burned into the terminal and cannot be modified. It can be used to identify and track CDMA mobile devices
IMEI is the ID card of mobile phone, MEID is the special ID card of CDMA system (operated by telecommunication); IMEI is 15 bits, MEID is 14 bits
Device "Id" the serial number provided by Android system for developers to identify mobile devices; it returns IMEI, MEID or ESN code according to different mobile devices; it returns the real identification of the device (therefore, the updated privacy protection on Android 10 cannot be obtained normally)
When the device is started for the first time, the system will randomly generate a 64 bit number and save it as a hexadecimal string. This value will be reset when the device is wired (wipe: reset the phone to factory settings, swipe or other similar operations)
Serial Number SN code is the abbreviation of Serial Number, sometimes called SerialNo, which is the product Serial Number. Product serial is a concept introduced to verify the "legal identity of products". It is used to protect the legitimate rights and interests of users and enjoy legal services. A set of genuine products only corresponds to a set of product serial numbers. SN code nickname: machine code, authentication code, registration application code, etc
MAC ADDRESS media access control address, also known as LAN Address, Ethernet Address or Physical Address, is an address used to confirm the location of network devices. In the OSI model, the third layer network layer is responsible for IP address, and the second layer data link layer is responsible for MAC ADDRESS. MAC ADDRESS is used to uniquely identify a network card in the network. If a device has one or more network cards, each network card needs and will have a unique MAC ADDRESS. Please refer to WIKI for details
ESN (Electronic Serial Number) the unique parameter of each mobile device (such as mobile phone, smartphone, tablet, etc.) specified by the Federal Communications Commission, with a length of 32 bits
ESN code was first used on amps and D-AMPS mobile phones, but now it is most common on CDMA mobile phones; IMEI is most commonly used on GSM mobile phones

77 original articles published, 37 praised, 50000 visitors+
Private letter follow

Tags: Mac Mobile Android network

Posted on Tue, 14 Jan 2020 23:08:12 -0800 by thepreacher