Merge "Surface: add getRemovedBuffer API" into oc-dev
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 381e90c..c604ca0 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -289,6 +289,46 @@
     return 0;
 }
 
+/**
+ * Ensure that we have a hard-limit quota to protect against abusive apps;
+ * they should never use more than 90% of blocks or 50% of inodes.
+ */
+static int prepare_app_quota(const std::unique_ptr<std::string>& uuid, const std::string& device,
+        uid_t uid) {
+    if (device.empty()) return 0;
+
+    struct dqblk dq;
+    if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), device.c_str(), uid,
+            reinterpret_cast<char*>(&dq)) != 0) {
+        PLOG(WARNING) << "Failed to find quota for " << uid;
+        return -1;
+    }
+
+    if ((dq.dqb_bhardlimit == 0) || (dq.dqb_ihardlimit == 0)) {
+        auto path = create_data_path(uuid ? uuid->c_str() : nullptr);
+        struct statvfs stat;
+        if (statvfs(path.c_str(), &stat) != 0) {
+            PLOG(WARNING) << "Failed to statvfs " << path;
+            return -1;
+        }
+
+        dq.dqb_valid = QIF_LIMITS;
+        dq.dqb_bhardlimit = (((stat.f_blocks * stat.f_frsize) / 10) * 9) / QIF_DQBLKSIZE;
+        dq.dqb_ihardlimit = (stat.f_files / 2);
+        if (quotactl(QCMD(Q_SETQUOTA, USRQUOTA), device.c_str(), uid,
+                reinterpret_cast<char*>(&dq)) != 0) {
+            PLOG(WARNING) << "Failed to set hard quota for " << uid;
+            return -1;
+        } else {
+            LOG(DEBUG) << "Applied hard quotas for " << uid;
+            return 0;
+        }
+    } else {
+        // Hard quota already set; assume it's reasonable
+        return 0;
+    }
+}
+
 binder::Status InstalldNativeService::createAppData(const std::unique_ptr<std::string>& uuid,
         const std::string& packageName, int32_t userId, int32_t flags, int32_t appId,
         const std::string& seInfo, int32_t targetSdkVersion, int64_t* _aidl_return) {
@@ -358,6 +398,10 @@
             return error("Failed to restorecon " + path);
         }
 
+        if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid), uid)) {
+            return error("Failed to set hard quota " + path);
+        }
+
         if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
             const std::string profile_dir =
                     create_primary_current_profile_package_dir_path(userId, pkgname);
@@ -709,6 +753,14 @@
             }
         }
     }
+
+    // Data under /data/media doesn't have an app, but we still want
+    // to limit it to prevent abuse.
+    if (prepare_app_quota(uuid, findQuotaDeviceForUuid(uuid),
+            multiuser_get_uid(userId, AID_MEDIA_RW))) {
+        return error("Failed to set hard quota for media_rw");
+    }
+
     return ok();
 }
 
@@ -2006,6 +2058,17 @@
                     reinterpret_cast<char*>(&dq)) == 0) {
                 LOG(DEBUG) << "Found " << source << " with quota";
                 mQuotaDevices[target] = source;
+
+                // ext4 only enables DQUOT_USAGE_ENABLED by default, so we
+                // need to kick it again to enable DQUOT_LIMITS_ENABLED.
+                if (quotactl(QCMD(Q_QUOTAON, USRQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable USRQUOTA on " << source;
+                }
+                if (quotactl(QCMD(Q_QUOTAON, GRPQUOTA), source.c_str(), QFMT_VFS_V1, nullptr) != 0
+                        && errno != EBUSY) {
+                    PLOG(ERROR) << "Failed to enable GRPQUOTA on " << source;
+                }
             }
         }
     }
diff --git a/cmds/installd/tests/installd_cache_test.cpp b/cmds/installd/tests/installd_cache_test.cpp
index 360f71a..174ce77 100644
--- a/cmds/installd/tests/installd_cache_test.cpp
+++ b/cmds/installd/tests/installd_cache_test.cpp
@@ -99,7 +99,7 @@
 static int64_t free() {
     struct statvfs buf;
     if (!statvfs("/data/local/tmp", &buf)) {
-        return buf.f_bavail * buf.f_bsize;
+        return buf.f_bavail * buf.f_frsize;
     } else {
         PLOG(ERROR) << "Failed to statvfs";
         return -1;
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index fbe6edf..24c0b45 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -629,11 +629,10 @@
     return res;
 }
 
-int64_t data_disk_free(const std::string& data_path)
-{
+int64_t data_disk_free(const std::string& data_path) {
     struct statvfs sfs;
     if (statvfs(data_path.c_str(), &sfs) == 0) {
-        return sfs.f_bavail * sfs.f_bsize;
+        return sfs.f_bavail * sfs.f_frsize;
     } else {
         PLOG(ERROR) << "Couldn't statvfs " << data_path;
         return -1;
@@ -1030,6 +1029,10 @@
     } else if (st.st_gid == gid && actual_mode == target_mode) {
         // Everything looks good!
         return 0;
+    } else {
+        // Mismatched GID/mode is recoverable; fall through to update
+        LOG(DEBUG) << "Mismatched cache GID/mode at " << path << ": found " << st.st_gid
+                << " but expected " << gid;
     }
 
     // Directory is owned correctly, but GID or mode mismatch means it's
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index aee7bd8..aec211a 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -1,5 +1,5 @@
 service servicemanager /system/bin/servicemanager
-    class core
+    class core animation
     user system
     group system readproc
     critical
@@ -12,4 +12,3 @@
     onrestart restart drm
     onrestart restart cameraserver
     writepid /dev/cpuset/system-background/tasks
-
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 8acdfed..d4e4dc3 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -287,6 +287,9 @@
     }
 
     if (item->mGraphicBuffer != NULL) {
+        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+            freeBufferLocked(item->mSlot);
+        }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
     }
 
diff --git a/libs/hwc2on1adapter/HWC2On1Adapter.cpp b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
index 03297ca..e35bfc9 100644
--- a/libs/hwc2on1adapter/HWC2On1Adapter.cpp
+++ b/libs/hwc2on1adapter/HWC2On1Adapter.cpp
@@ -538,6 +538,12 @@
     for (auto& change : mChanges->getTypeChanges()) {
         auto layerId = change.first;
         auto type = change.second;
+        if (mDevice.mLayers.count(layerId) == 0) {
+            // This should never happen but somehow does.
+            ALOGW("Cannot accept change for unknown layer (%" PRIu64 ")",
+                  layerId);
+            continue;
+        }
         auto layer = mDevice.mLayers[layerId];
         layer->setCompositionType(type);
     }
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 1ed150b..a38b4dc 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -28,6 +28,7 @@
 #include <ui/GraphicBuffer.h>
 #include <system/graphics.h>
 #include <hardware/gralloc1.h>
+#include <grallocusage/GrallocUsageConversion.h>
 
 #include <private/android/AHardwareBufferHelpers.h>
 
@@ -100,8 +101,12 @@
     outDesc->width = gbuffer->getWidth();
     outDesc->height = gbuffer->getHeight();
     outDesc->layers = gbuffer->getLayerCount();
+
+    uint64_t producerUsage = 0;
+    uint64_t consumerUsage = 0;
+    android_convertGralloc0To1Usage(gbuffer->getUsage(), &producerUsage, &consumerUsage);
     AHardwareBuffer_convertFromGrallocUsageBits(&outDesc->usage0, &outDesc->usage1,
-            gbuffer->getUsage(), gbuffer->getUsage());
+            producerUsage, consumerUsage);
     outDesc->format = AHardwareBuffer_convertFromPixelFormat(
             static_cast<uint32_t>(gbuffer->getPixelFormat()));
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 04358dc..834c1c4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2840,15 +2840,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2872,6 +2874,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 581bbfd..4ecbddd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -364,6 +364,8 @@
             uint32_t w, uint32_t h, uint32_t flags, sp<IBinder>* outHandle,
             sp<IGraphicBufferProducer>* outGbp, sp<Layer>* outLayer);
 
+    String8 getUniqueLayerName(const String8& name);
+
     // called in response to the window-manager calling
     // ISurfaceComposerClient::destroySurface()
     status_t onLayerRemoved(const sp<Client>& client, const sp<IBinder>& handle);
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index c26847f..a6c0b9c 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -2637,15 +2637,17 @@
 
     sp<Layer> layer;
 
+    String8 uniqueName = getUniqueLayerName(name);
+
     switch (flags & ISurfaceComposerClient::eFXSurfaceMask) {
         case ISurfaceComposerClient::eFXSurfaceNormal:
             result = createNormalLayer(client,
-                    name, w, h, flags, format,
+                    uniqueName, w, h, flags, format,
                     handle, gbp, &layer);
             break;
         case ISurfaceComposerClient::eFXSurfaceDim:
             result = createDimLayer(client,
-                    name, w, h, flags,
+                    uniqueName, w, h, flags,
                     handle, gbp, &layer);
             break;
         default:
@@ -2669,6 +2671,30 @@
     return result;
 }
 
+String8 SurfaceFlinger::getUniqueLayerName(const String8& name)
+{
+    bool matchFound = true;
+    uint32_t dupeCounter = 0;
+
+    // Tack on our counter whether there is a hit or not, so everyone gets a tag
+    String8 uniqueName = name + "#" + String8(std::to_string(dupeCounter).c_str());
+
+    // Loop over layers until we're sure there is no matching name
+    while (matchFound) {
+        matchFound = false;
+        mDrawingState.traverseInZOrder([&](Layer* layer) {
+            if (layer->getName() == uniqueName) {
+                matchFound = true;
+                uniqueName = name + "#" + String8(std::to_string(++dupeCounter).c_str());
+            }
+        });
+    }
+
+    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+
+    return uniqueName;
+}
+
 status_t SurfaceFlinger::createNormalLayer(const sp<Client>& client,
         const String8& name, uint32_t w, uint32_t h, uint32_t flags, PixelFormat& format,
         sp<IBinder>* handle, sp<IGraphicBufferProducer>* gbp, sp<Layer>* outLayer)
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index 435aa0c..0b482f7 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -1,5 +1,5 @@
 service surfaceflinger /system/bin/surfaceflinger
-    class core
+    class core animation
     user system
     group graphics drmrpc readproc
     onrestart restart zygote