Before the first call to clearCallingIdentity, cache the calling package.

Then it will be saved as a mutator when the dirty bit is set.
This may be accessed by multiple threads, so the data is cached in ThreadLocal.
Also track the calling Uid, and clear the cached package when the tracked Uid
is restored.

Bug: 18421411
Change-Id: I4597bd4169636c3988d72ddde51578a02af193ea
diff --git a/src/com/android/providers/calendar/CalendarProvider2.java b/src/com/android/providers/calendar/CalendarProvider2.java
index 9af4c77..5002177 100644
--- a/src/com/android/providers/calendar/CalendarProvider2.java
+++ b/src/com/android/providers/calendar/CalendarProvider2.java
@@ -834,11 +834,11 @@
     @Override
     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
             String sortOrder) {
-        final long identity = Binder.clearCallingIdentity();
+        final long identity = clearCallingIdentityInternal();
         try {
             return queryInternal(uri, projection, selection, selectionArgs, sortOrder);
         } finally {
-            Binder.restoreCallingIdentity(identity);
+            restoreCallingIdentityInternal(identity);
         }
     }
 
@@ -5074,6 +5074,11 @@
     }
 
     private String getCallingPackageName() {
+        if (getCachedCallingPackage() != null) {
+            // If the calling package is null, use the best available as a fallback.
+            return getCachedCallingPackage();
+        }
+
         final PackageManager pm = getContext().getPackageManager();
         final int uid = Binder.getCallingUid();
         final String[] packages = pm.getPackagesForUid(uid);
diff --git a/src/com/android/providers/calendar/SQLiteContentProvider.java b/src/com/android/providers/calendar/SQLiteContentProvider.java
index ad0e028..01afb23 100644
--- a/src/com/android/providers/calendar/SQLiteContentProvider.java
+++ b/src/com/android/providers/calendar/SQLiteContentProvider.java
@@ -27,6 +27,7 @@
 import android.database.sqlite.SQLiteTransactionListener;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Process;
 import android.provider.CalendarContract;
 
 import java.util.ArrayList;
@@ -93,7 +94,7 @@
         if (!applyingBatch) {
             mDb = mOpenHelper.getWritableDatabase();
             mDb.beginTransactionWithListener(this);
-            final long identity = Binder.clearCallingIdentity();
+            final long identity = clearCallingIdentityInternal();
             try {
                 result = insertInTransaction(uri, values, isCallerSyncAdapter);
                 if (result != null) {
@@ -101,7 +102,7 @@
                 }
                 mDb.setTransactionSuccessful();
             } finally {
-                Binder.restoreCallingIdentity(identity);
+                restoreCallingIdentityInternal(identity);
                 mDb.endTransaction();
             }
 
@@ -121,7 +122,7 @@
         boolean isCallerSyncAdapter = getIsCallerSyncAdapter(uri);
         mDb = mOpenHelper.getWritableDatabase();
         mDb.beginTransactionWithListener(this);
-        final long identity = Binder.clearCallingIdentity();
+        final long identity = clearCallingIdentityInternal();
         try {
             for (int i = 0; i < numValues; i++) {
                 Uri result = insertInTransaction(uri, values[i], isCallerSyncAdapter);
@@ -132,7 +133,7 @@
             }
             mDb.setTransactionSuccessful();
         } finally {
-            Binder.restoreCallingIdentity(identity);
+            restoreCallingIdentityInternal(identity);
             mDb.endTransaction();
         }
 
@@ -148,7 +149,7 @@
         if (!applyingBatch) {
             mDb = mOpenHelper.getWritableDatabase();
             mDb.beginTransactionWithListener(this);
-            final long identity = Binder.clearCallingIdentity();
+            final long identity = clearCallingIdentityInternal();
             try {
                 count = updateInTransaction(uri, values, selection, selectionArgs,
                             isCallerSyncAdapter);
@@ -157,7 +158,7 @@
                 }
                 mDb.setTransactionSuccessful();
             } finally {
-                Binder.restoreCallingIdentity(identity);
+                restoreCallingIdentityInternal(identity);
                 mDb.endTransaction();
             }
 
@@ -181,7 +182,7 @@
         if (!applyingBatch) {
             mDb = mOpenHelper.getWritableDatabase();
             mDb.beginTransactionWithListener(this);
-            final long identity = Binder.clearCallingIdentity();
+            final long identity = clearCallingIdentityInternal();
             try {
                 count = deleteInTransaction(uri, selection, selectionArgs, isCallerSyncAdapter);
                 if (count > 0) {
@@ -189,7 +190,7 @@
                 }
                 mDb.setTransactionSuccessful();
             } finally {
-                Binder.restoreCallingIdentity(identity);
+                restoreCallingIdentityInternal(identity);
                 mDb.endTransaction();
             }
 
@@ -222,7 +223,7 @@
         mDb = mOpenHelper.getWritableDatabase();
         mDb.beginTransactionWithListener(this);
         final boolean isCallerSyncAdapter = getIsCallerSyncAdapter(operations.get(0).getUri());
-        final long identity = Binder.clearCallingIdentity();
+        final long identity = clearCallingIdentityInternal();
         try {
             mApplyingBatch.set(true);
             final ContentProviderResult[] results = new ContentProviderResult[numOperations];
@@ -239,7 +240,7 @@
             mApplyingBatch.set(false);
             mDb.endTransaction();
             onEndTransaction(!isCallerSyncAdapter);
-            Binder.restoreCallingIdentity(identity);
+            restoreCallingIdentityInternal(identity);
         }
     }
 
@@ -274,4 +275,58 @@
      * Some URI's are maintained locally so we should not request a sync for them
      */
     protected abstract boolean shouldSyncFor(Uri uri);
+
+    /** The package to most recently query(), not including further internally recursive calls. */
+    private final ThreadLocal<String> mCallingPackage = new ThreadLocal<String>();
+
+    /**
+     * The calling Uid when a calling package is cached, so we know when the stack of any
+     * recursive calls to clearCallingIdentity and restoreCallingIdentity is complete.
+     */
+    private final ThreadLocal<Integer> mOriginalCallingUid = new ThreadLocal<Integer>();
+
+
+    protected String getCachedCallingPackage() {
+        return mCallingPackage.get();
+    }
+
+    /**
+     * Call {@link android.os.Binder#clearCallingIdentity()}, while caching the calling package
+     * name, so that it can be saved if this is part of an event mutation.
+     */
+    protected long clearCallingIdentityInternal() {
+        // Only set the calling package if the calling UID is not our own.
+        int uid = Process.myUid();
+        int callingUid = Binder.getCallingUid();
+        if (uid != callingUid) {
+            try {
+                mOriginalCallingUid.set(callingUid);
+                String callingPackage = getCallingPackage();
+                mCallingPackage.set(callingPackage);
+            } catch (SecurityException e) {
+                // If this exception is thrown, clearCallingIdentity has already been called, and
+                // calling package is already available.
+            }
+        }
+
+        return Binder.clearCallingIdentity();
+    }
+
+    /**
+     * Call {@link Binder#restoreCallingIdentity(long)}.
+     * </p>
+     * If this is the last restore on the stack of calls to
+     * {@link android.os.Binder#clearCallingIdentity()}, then the cached calling package will also
+     * be cleared.
+     * @param identity
+     */
+    protected void restoreCallingIdentityInternal(long identity) {
+        Binder.restoreCallingIdentity(identity);
+
+        int callingUid = Binder.getCallingUid();
+        if (mOriginalCallingUid.get() != null && mOriginalCallingUid.get() == callingUid) {
+            mCallingPackage.set(null);
+            mOriginalCallingUid.set(null);
+        }
+    }
 }