Move device serial behing a permission

Build serial is non-user resettable freely available deivice
identifier. It can be used by ad-netowrks to track the user
across apps which violates the user's privacy.

This change deprecates Build.SERIAL and adds a new Build.getSerial()
API which requires holding the read_phone_state permission.
The Build.SERIAL value is set to "undefined" for apps targeting
high enough SDK and for legacy app the value is still available.

bug:31402365

Change-Id: Iddd13430b2bd1d9ab4966e31038ecabdbdcec06d
diff --git a/Android.mk b/Android.mk
index 6831945..8977433 100644
--- a/Android.mk
+++ b/Android.mk
@@ -221,6 +221,7 @@
 	core/java/android/os/IBatteryPropertiesListener.aidl \
 	core/java/android/os/IBatteryPropertiesRegistrar.aidl \
 	core/java/android/os/ICancellationSignal.aidl \
+	core/java/android/os/IDeviceIdentifiersPolicyService.aidl \
 	core/java/android/os/IDeviceIdleController.aidl \
 	core/java/android/os/IHardwarePropertiesManager.aidl \
 	core/java/android/os/IMaintenanceActivityListener.aidl \
diff --git a/api/current.txt b/api/current.txt
index fc3c747..6a182f0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -28370,6 +28370,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -28385,7 +28386,7 @@
     field public static final java.lang.String MODEL;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/api/system-current.txt b/api/system-current.txt
index 8565e64..d5ec878 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -30852,6 +30852,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -30868,7 +30869,7 @@
     field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/api/test-current.txt b/api/test-current.txt
index 3fb0c69..d94e712 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -28442,6 +28442,7 @@
   public class Build {
     ctor public Build();
     method public static java.lang.String getRadioVersion();
+    method public static java.lang.String getSerial();
     field public static final java.lang.String BOARD;
     field public static final java.lang.String BOOTLOADER;
     field public static final java.lang.String BRAND;
@@ -28457,7 +28458,7 @@
     field public static final java.lang.String MODEL;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
-    field public static final java.lang.String SERIAL;
+    field public static final deprecated java.lang.String SERIAL;
     field public static final java.lang.String[] SUPPORTED_32_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_64_BIT_ABIS;
     field public static final java.lang.String[] SUPPORTED_ABIS;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 4ca1af8..387a1f5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -128,6 +128,8 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
 import java.net.InetAddress;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -517,6 +519,7 @@
         boolean persistent;
         Configuration config;
         CompatibilityInfo compatInfo;
+        String buildSerial;
 
         /** Initial values for {@link Profiler}. */
         ProfilerInfo initProfilerInfo;
@@ -851,7 +854,8 @@
                 IUiAutomationConnection instrumentationUiConnection, int debugMode,
                 boolean enableBinderTracking, boolean trackAllocation,
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
-                CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings) {
+                CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+                String buildSerial) {
 
             if (services != null) {
                 // Setup the service cache in the ServiceManager
@@ -876,6 +880,7 @@
             data.config = config;
             data.compatInfo = compatInfo;
             data.initProfilerInfo = profilerInfo;
+            data.buildSerial = buildSerial;
             sendMessage(H.BIND_APPLICATION, data);
         }
 
@@ -5182,6 +5187,18 @@
             StrictMode.enableDeathOnFileUriExposure();
         }
 
+        // We deprecated Build.SERIAL and only apps that target pre NMR1
+        // SDK can see it. Since access to the serial is now behind a
+        // permission we push down the value and here we fix it up
+        // before any app code has been loaded.
+        try {
+            Field field = Build.class.getDeclaredField("SERIAL");
+            field.setAccessible(true);
+            field.set(Build.class, data.buildSerial);
+        } catch (NoSuchFieldException | IllegalAccessException e) {
+            /* ignore */
+        }
+
         if (data.debugMode != IApplicationThread.DEBUG_OFF) {
             // XXX should have option to change the port.
             Debug.changeDebugPort(8100);
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 3063d98..e41c841 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -301,10 +301,11 @@
             CompatibilityInfo compatInfo = CompatibilityInfo.CREATOR.createFromParcel(data);
             HashMap<String, IBinder> services = data.readHashMap(null);
             Bundle coreSettings = data.readBundle();
+            String buildSerial = data.readString();
             bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
                     testWatcher, uiAutomationConnection, testMode, enableBinderTracking,
                     trackAllocation, restrictedBackupMode, persistent, config, compatInfo, services,
-                    coreSettings);
+                    coreSettings, buildSerial);
             return true;
         }
 
@@ -1058,7 +1059,8 @@
             IUiAutomationConnection uiAutomationConnection, int debugMode,
             boolean enableBinderTracking, boolean trackAllocation, boolean restrictedBackupMode,
             boolean persistent, Configuration config, CompatibilityInfo compatInfo,
-            Map<String, IBinder> services, Bundle coreSettings) throws RemoteException {
+            Map<String, IBinder> services, Bundle coreSettings, String buildSerial)
+            throws RemoteException {
         Parcel data = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
         data.writeString(packageName);
@@ -1088,6 +1090,7 @@
         compatInfo.writeToParcel(data, 0);
         data.writeMap(services);
         data.writeBundle(coreSettings);
+        data.writeString(buildSerial);
         mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
                 IBinder.FLAG_ONEWAY);
         data.recycle();
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 7732157..ac8b1c4 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -98,8 +98,8 @@
             IInstrumentationWatcher testWatcher, IUiAutomationConnection uiAutomationConnection,
             int debugMode, boolean enableBinderTracking, boolean trackAllocation,
             boolean restrictedBackupMode, boolean persistent, Configuration config,
-            CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings)
-            throws RemoteException;
+            CompatibilityInfo compatInfo, Map<String, IBinder> services, Bundle coreSettings,
+            String buildSerial) throws RemoteException;
     void scheduleExit() throws RemoteException;
     void scheduleSuicide() throws RemoteException;
     void scheduleConfigurationChanged(Configuration config) throws RemoteException;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b295919..457866b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3675,6 +3675,12 @@
     public static final String GATEKEEPER_SERVICE = "android.service.gatekeeper.IGateKeeperService";
 
     /**
+     * Service defining the policy for access to device identifiers.
+     * @hide
+     */
+    public static final String DEVICE_IDENTIFIERS_SERVICE = "device_identifiers";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 5b51002..0191589 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,7 +16,10 @@
 
 package android.os;
 
+import android.Manifest;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.content.Context;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -98,8 +101,35 @@
      */
     public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
 
-    /** A hardware serial number, if available.  Alphanumeric only, case-insensitive. */
-    public static final String SERIAL = getString("ro.serialno");
+    /**
+     * A hardware serial number, if available. Alphanumeric only, case-insensitive.
+     * For apps targeting SDK higher than {@link Build.VERSION_CODES#N_MR1} this
+     * field is set to {@link Build#UNKNOWN}.
+     *
+     * @deprecated Use {@link #getSerial()} instead.
+     **/
+    @Deprecated
+    // IMPORTANT: This field should be initialized via a function call to
+    // prevent its value being inlined in the app during compilation because
+    // we will later set it to the value based on the app's target SDK.
+    public static final String SERIAL = getString("no.such.thing");
+
+    /**
+     * Gets the hardware serial, if available. Requires holding the {@link
+     * android.Manifest.permission#READ_PHONE_STATE} permission.
+     * @return The serial if specified.
+     */
+    @RequiresPermission(Manifest.permission.READ_PHONE_STATE)
+    public static String getSerial() {
+        IDeviceIdentifiersPolicyService service = IDeviceIdentifiersPolicyService.Stub
+                .asInterface(ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE));
+        try {
+            return service.getSerial();
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+        return UNKNOWN;
+    }
 
     /**
      * An ordered list of ABIs supported by this device. The most preferred ABI is the first
diff --git a/core/java/android/os/IDeviceIdentifiersPolicyService.aidl b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
new file mode 100644
index 0000000..ac19f2b
--- /dev/null
+++ b/core/java/android/os/IDeviceIdentifiersPolicyService.aidl
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+/**
+ * @hide
+ */
+interface IDeviceIdentifiersPolicyService {
+    String getSerial();
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 96706c0..ba4f041 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.am;
 
+import android.os.IDeviceIdentifiersPolicyService;
 import com.android.internal.telephony.TelephonyIntents;
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
@@ -6516,6 +6517,17 @@
             }
             ProfilerInfo profilerInfo = profileFile == null ? null
                     : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
+
+            // We deprecated Build.SERIAL and only apps that target pre NMR1
+            // SDK can see it. Since access to the serial is now behind a
+            // permission we push down the value.
+            String buildSerial = Build.UNKNOWN;
+            if (appInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+                buildSerial = IDeviceIdentifiersPolicyService.Stub.asInterface(
+                        ServiceManager.getService(Context.DEVICE_IDENTIFIERS_SERVICE))
+                        .getSerial();
+            }
+
             thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                     profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                     app.instrumentationUiAutomationConnection, testMode,
@@ -6523,7 +6535,9 @@
                     isRestrictedBackupMode || !normalMode, app.persistent,
                     new Configuration(mConfiguration), app.compat,
                     getCommonServicesLocked(app.isolated),
-                    mCoreSettingsObserver.getCoreSettingsLocked());
+                    mCoreSettingsObserver.getCoreSettingsLocked(),
+                    buildSerial);
+
             updateLruProcessLocked(app, false, null);
             app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
         } catch (Exception e) {
diff --git a/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
new file mode 100644
index 0000000..759030b
--- /dev/null
+++ b/services/core/java/com/android/server/os/DeviceIdentifiersPolicyService.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.os;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Binder;
+import android.os.Build;
+import android.os.IDeviceIdentifiersPolicyService;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import com.android.server.SystemService;
+
+/**
+ * This service defines the policy for accessing device identifiers.
+ */
+public final class DeviceIdentifiersPolicyService extends SystemService {
+    public DeviceIdentifiersPolicyService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(Context.DEVICE_IDENTIFIERS_SERVICE,
+                new DeviceIdentifiersPolicy(getContext()));
+    }
+
+    private static final class DeviceIdentifiersPolicy
+            extends IDeviceIdentifiersPolicyService.Stub {
+        private final @NonNull Context mContext;
+
+        public DeviceIdentifiersPolicy(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public @Nullable String getSerial() throws RemoteException {
+            if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) {
+                mContext.enforceCallingOrSelfPermission(
+                        Manifest.permission.READ_PHONE_STATE, "getSerial");
+            }
+            return SystemProperties.get("ro.serialno", Build.UNKNOWN);
+        }
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4591fcc..fb4ea30 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -16,7 +16,6 @@
 
 package com.android.server;
 
-import android.app.ActivityManagerNative;
 import android.app.ActivityThread;
 import android.app.INotificationManager;
 import android.app.usage.UsageStatsManagerInternal;
@@ -32,7 +31,6 @@
 import android.os.Environment;
 import android.os.FactoryTest;
 import android.os.FileUtils;
-import android.os.IPowerManager;
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.RemoteException;
@@ -79,6 +77,7 @@
 import com.android.server.net.NetworkPolicyManagerService;
 import com.android.server.net.NetworkStatsService;
 import com.android.server.notification.NotificationManagerService;
+import com.android.server.os.DeviceIdentifiersPolicyService;
 import com.android.server.os.SchedulingPolicyService;
 import com.android.server.pm.BackgroundDexOptService;
 import com.android.server.pm.Installer;
@@ -427,6 +426,12 @@
         Installer installer = mSystemServiceManager.startService(Installer.class);
         traceEnd();
 
+        // In some cases after launching an app we need to access device identifiers,
+        // therefore register the device identifier policy before the activity manager.
+        traceBeginAndSlog("DeviceIdentifiersPolicyService");
+        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);
+        traceEnd();
+
         // Activity manager runs the show.
         traceBeginAndSlog("StartActivityManager");
         mActivityManagerService = mSystemServiceManager.startService(