Add storage health API for DeviceDiagnostics.

This adds a system API for reading UFS health indicators, as a
percentage of remaining useful lifetime.

Bug: 309886423
Test: DeviceDiagnostics can read storage health
Change-Id: If3a42baf7f61e2018968af4a920ee63908be5fc6
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 94cde98..f3f1d0d 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -11049,6 +11049,7 @@
     method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException;
     method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException;
     method @RequiresPermission(android.Manifest.permission.WRITE_MEDIA_STORAGE) public int getExternalStorageMountMode(int, @NonNull String);
+    method @FlaggedApi("android.os.storage_lifetime_api") @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getInternalStorageRemainingLifetime();
     method public static boolean hasIsolatedStorage();
     method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException;
     field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index 82518bf..6c728a4 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -114,3 +114,11 @@
     is_fixed_read_only: true
     bug: "309792384"
 }
+
+flag {
+    name: "storage_lifetime_api"
+    namespace: "phoenix"
+    description: "Feature flag for adding storage component health APIs."
+    is_fixed_read_only: true
+    bug: "309792384"
+}
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 54ed73c..1ab48a2 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -175,4 +175,12 @@
     void setCloudMediaProvider(in String authority) = 96;
     String getCloudMediaProvider() = 97;
     long getInternalStorageBlockDeviceSize() = 98;
-}
\ No newline at end of file
+    /**
+     * Returns the remaining lifetime of the internal storage device, as an
+     * integer percentage. For example, 90 indicates that 90% of the storage
+     * device's useful lifetime remains. If no information is available, -1
+     * is returned.
+     */
+    @EnforcePermission("READ_PRIVILEGED_PHONE_STATE")
+    int getInternalStorageRemainingLifetime() = 99;
+}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 9587db1..efcfb90 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -28,6 +28,7 @@
 
 import android.annotation.BytesLong;
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -58,6 +59,7 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
+import android.os.Flags;
 import android.os.Handler;
 import android.os.IInstalld;
 import android.os.IVold;
@@ -2945,4 +2947,24 @@
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static final int CRYPT_TYPE_DEFAULT = 1;
+
+    /**
+     * Returns the remaining lifetime of the internal storage device, as an integer percentage. For
+     * example, 90 indicates that 90% of the storage device's useful lifetime remains. If no
+     * information is available, -1 is returned.
+     *
+     * @return Percentage of the remaining useful lifetime of the internal storage device.
+     *
+     * @hide
+     */
+    @FlaggedApi(Flags.FLAG_STORAGE_LIFETIME_API)
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    public int getInternalStorageRemainingLifetime() {
+        try {
+            return mStorageManager.getInternalStorageRemainingLifetime();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index ea1b0f5..e7fae24 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -48,6 +48,7 @@
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.annotation.EnforcePermission;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -3597,6 +3598,13 @@
         return mInternalStorageSize;
     }
 
+    @EnforcePermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+    @Override
+    public int getInternalStorageRemainingLifetime() throws RemoteException {
+        super.getInternalStorageRemainingLifetime_enforcePermission();
+        return mVold.getStorageRemainingLifetime();
+    }
+
     /**
      * Enforces that the caller is the {@link ExternalStorageService}
      *