Use VMRuntime.isBootClassPathOnDisk

Bug: 17679443
Change-Id: If53c236058a7237d735c2344a715cf0a36301f9b
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f2b7d7b..081f8ae 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1696,6 +1696,7 @@
   <java-symbol type="string" name="launch_warning_replace" />
   <java-symbol type="string" name="launch_warning_title" />
   <java-symbol type="string" name="low_internal_storage_view_text" />
+  <java-symbol type="string" name="low_internal_storage_view_text_no_boot" />
   <java-symbol type="string" name="low_internal_storage_view_title" />
   <java-symbol type="string" name="notification_listener_binding_label" />
   <java-symbol type="string" name="condition_provider_service_binding_label" />
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 27184390..851cf17 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4729,6 +4729,18 @@
         return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
     }
 
+    /**
+     * Returns deduplicated list of supported instructions for dex code.
+     */
+    public static String[] getAllDexCodeInstructionSets() {
+        String[] supportedInstructionSets = new String[Build.SUPPORTED_ABIS.length];
+        for (int i = 0; i < supportedInstructionSets.length; i++) {
+            String abi = Build.SUPPORTED_ABIS[i];
+            supportedInstructionSets[i] = VMRuntime.getInstructionSet(abi);
+        }
+        return getDexCodeInstructionSets(supportedInstructionSets);
+    }
+
     @Override
     public void forceDexOpt(String packageName) {
         enforceSystemOrRoot("forceDexOpt");
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index 468a344..111c09b 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -18,6 +18,7 @@
 
 import com.android.server.EventLogTags;
 import com.android.server.SystemService;
+import com.android.server.pm.PackageManagerService;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -51,6 +52,8 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
+import dalvik.system.VMRuntime;
+
 /**
  * This class implements a service to monitor the amount of disk
  * storage space on the device.  If the free storage on device is less
@@ -89,6 +92,7 @@
     private long mLastReportedFreeMemTime;
     boolean mLowMemFlag=false;
     private boolean mMemFullFlag=false;
+    private final boolean mIsBootImageOnDisk;
     private final ContentResolver mResolver;
     private final long mTotalMemory;  // on /data
     private final StatFs mDataFileStats;
@@ -285,6 +289,10 @@
                     mLowMemFlag = false;
                 }
             }
+            if (!mLowMemFlag && !mIsBootImageOnDisk) {
+                Slog.i(TAG, "No boot image on disk due to lack of space. Sending notification");
+                sendNotification();
+            }
             if (mFreeMem < mMemFullThreshold) {
                 if (!mMemFullFlag) {
                     sendFullNotification();
@@ -314,6 +322,7 @@
         super(context);
         mLastReportedFreeMemTime = 0;
         mResolver = context.getContentResolver();
+        mIsBootImageOnDisk = isBootImageOnDisk();
         //create StatFs object
         mDataFileStats = new StatFs(DATA_PATH.getAbsolutePath());
         mSystemFileStats = new StatFs(SYSTEM_PATH.getAbsolutePath());
@@ -331,6 +340,15 @@
         mStorageNotFullIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
     }
 
+    private static boolean isBootImageOnDisk() {
+        for (String instructionSet : PackageManagerService.getAllDexCodeInstructionSets()) {
+            if (!VMRuntime.isBootClassPathOnDisk(instructionSet)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
     * Initializes the disk space threshold value and posts an empty message to
     * kickstart the process.
@@ -364,7 +382,7 @@
 
         @Override
         public boolean isMemoryLow() {
-            return mLowMemFlag;
+            return mLowMemFlag || !mIsBootImageOnDisk;
         }
 
         @Override
@@ -409,6 +427,7 @@
 
         pw.print("  mLowMemFlag="); pw.print(mLowMemFlag);
         pw.print(" mMemFullFlag="); pw.println(mMemFullFlag);
+        pw.print(" mIsBootImageOnDisk="); pw.print(mIsBootImageOnDisk);
 
         pw.print("  mClearSucceeded="); pw.print(mClearSucceeded);
         pw.print(" mClearingCache="); pw.println(mClearingCache);
@@ -445,19 +464,25 @@
                         Context.NOTIFICATION_SERVICE);
         CharSequence title = context.getText(
                 com.android.internal.R.string.low_internal_storage_view_title);
-        CharSequence details = context.getText(
-                com.android.internal.R.string.low_internal_storage_view_text);
+        CharSequence details = context.getText(mIsBootImageOnDisk
+                ? com.android.internal.R.string.low_internal_storage_view_text
+                : com.android.internal.R.string.low_internal_storage_view_text_no_boot);
         PendingIntent intent = PendingIntent.getActivityAsUser(context, 0,  lowMemIntent, 0,
                 null, UserHandle.CURRENT);
-        Notification notification = new Notification();
-        notification.icon = com.android.internal.R.drawable.stat_notify_disk_full;
-        notification.tickerText = title;
+        Notification notification = new Notification.Builder(context)
+                .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
+                .setTicker(title)
+                .setColor(context.getResources().getColor(
+                    com.android.internal.R.color.system_notification_accent_color))
+                .setContentTitle(title)
+                .setContentText(details)
+                .setContentIntent(intent)
+                .setStyle(new Notification.BigTextStyle()
+                      .bigText(details))
+                .setVisibility(Notification.VISIBILITY_PUBLIC)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .build();
         notification.flags |= Notification.FLAG_NO_CLEAR;
-        notification.color = context.getResources().getColor(
-                com.android.internal.R.color.system_notification_accent_color);
-        notification.setLatestEventInfo(context, title, details, intent);
-        notification.visibility = Notification.VISIBILITY_PUBLIC;
-        notification.category = Notification.CATEGORY_SYSTEM;
         mNotificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
                 UserHandle.ALL);
         context.sendStickyBroadcastAsUser(mStorageLowIntent, UserHandle.ALL);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 972c929..cfa4436 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -382,6 +382,10 @@
         File[] files = dir.listFiles();
         if (files != null) {
             for (File f : files) {
+                String path = f.getPath();
+                if (path.endsWith(".bak")) {
+                    f = new File(path.substring(0, path.length() - 4));
+                }
                 long beginTime = Long.parseLong(f.getName());
                 if (beginTime < expiryTime) {
                     new AtomicFile(f).delete();