Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 364fc14f authored by Jeff Sharkey's avatar Jeff Sharkey Committed by Android (Google) Code Review
Browse files

Merge "Detect wedged ContentProviders, treat as ANR." into klp-dev

parents fcd61bb5 7aa7601c
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -758,6 +758,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
            return true;
        }

        case APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
            appNotRespondingViaProvider(b);
            reply.writeNoException();
            return true;
        }

        case REMOVE_CONTENT_PROVIDER_TRANSACTION: {
            data.enforceInterface(IActivityManager.descriptor);
            IBinder b = data.readStrongBinder();
@@ -2891,6 +2899,7 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
        return res;
    }

    public void unstableProviderDied(IBinder connection) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
@@ -2902,6 +2911,18 @@ class ActivityManagerProxy implements IActivityManager
        reply.recycle();
    }

    @Override
    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(connection);
        mRemote.transact(APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }

    public void removeContentProvider(IBinder connection, boolean stable) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
+13 −0
Original line number Diff line number Diff line
@@ -4653,6 +4653,19 @@ public final class ActivityThread {
        }
    }

    final void appNotRespondingViaProvider(IBinder provider) {
        synchronized (mProviderMap) {
            ProviderRefCount prc = mProviderRefCountMap.get(provider);
            if (prc != null) {
                try {
                    ActivityManagerNative.getDefault()
                            .appNotRespondingViaProvider(prc.holder.connection);
                } catch (RemoteException e) {
                }
            }
        }
    }

    private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
            ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
        final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
+5 −0
Original line number Diff line number Diff line
@@ -2200,5 +2200,10 @@ class ContextImpl extends Context {
        public void unstableProviderDied(IContentProvider icp) {
            mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
        }

        @Override
        public void appNotRespondingViaProvider(IContentProvider icp) {
            mMainThread.appNotRespondingViaProvider(icp.asBinder());
        }
    }
}
+2 −0
Original line number Diff line number Diff line
@@ -139,6 +139,7 @@ public interface IActivityManager extends IInterface {
    public boolean refContentProvider(IBinder connection, int stableDelta, int unstableDelta)
            throws RemoteException;
    public void unstableProviderDied(IBinder connection) throws RemoteException;
    public void appNotRespondingViaProvider(IBinder connection) throws RemoteException;
    public PendingIntent getRunningServiceControlPanel(ComponentName service)
            throws RemoteException;
    public ComponentName startService(IApplicationThread caller, Intent service,
@@ -691,4 +692,5 @@ public interface IActivityManager extends IInterface {
    int TAKE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+179;
    int RELEASE_PERSISTABLE_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+180;
    int GET_PERSISTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+181;
    int APP_NOT_RESPONDING_VIA_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+182;
}
+133 −43
Original line number Diff line number Diff line
@@ -16,15 +16,20 @@

package android.content;

import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DeadObjectException;
import android.os.Handler;
import android.os.ICancellationSignal;
import android.os.RemoteException;
import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.content.res.AssetFileDescriptor;
import android.os.RemoteException;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;

import dalvik.system.CloseGuard;

@@ -45,26 +50,64 @@ import java.util.ArrayList;
 * until you are finished with the data they have returned.
 */
public class ContentProviderClient {
    private final IContentProvider mContentProvider;
    private static final String TAG = "ContentProviderClient";

    @GuardedBy("ContentProviderClient.class")
    private static Handler sAnrHandler;

    private final ContentResolver mContentResolver;
    private final IContentProvider mContentProvider;
    private final String mPackageName;
    private final boolean mStable;
    private boolean mReleased;

    private final CloseGuard mGuard = CloseGuard.get();

    /**
     * @hide
     */
    ContentProviderClient(ContentResolver contentResolver,
            IContentProvider contentProvider, boolean stable) {
        mContentProvider = contentProvider;
    private long mAnrTimeout;
    private NotRespondingRunnable mAnrRunnable;

    private boolean mReleased;

    /** {@hide} */
    ContentProviderClient(
            ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
        mContentResolver = contentResolver;
        mContentProvider = contentProvider;
        mPackageName = contentResolver.mPackageName;
        mStable = stable;

        mGuard.open("release");
    }

    /** {@hide} */
    public void setDetectNotResponding(long timeoutMillis) {
        synchronized (ContentProviderClient.class) {
            mAnrTimeout = timeoutMillis;

            if (timeoutMillis > 0) {
                if (mAnrRunnable == null) {
                    mAnrRunnable = new NotRespondingRunnable();
                }
                if (sAnrHandler == null) {
                    sAnrHandler = new Handler(Looper.getMainLooper(), null, true /* async */);
                }
            } else {
                mAnrRunnable = null;
            }
        }
    }

    private void beforeRemote() {
        if (mAnrRunnable != null) {
            sAnrHandler.postDelayed(mAnrRunnable, mAnrTimeout);
        }
    }

    private void afterRemote() {
        if (mAnrRunnable != null) {
            sAnrHandler.removeCallbacks(mAnrRunnable);
        }
    }

    /** See {@link ContentProvider#query ContentProvider.query} */
    public Cursor query(Uri url, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) throws RemoteException {
@@ -72,16 +115,16 @@ public class ContentProviderClient {
    }

    /** See {@link ContentProvider#query ContentProvider.query} */
    public Cursor query(Uri url, String[] projection, String selection,
            String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal)
                    throws RemoteException {
    public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs,
            String sortOrder, CancellationSignal cancellationSignal) throws RemoteException {
        beforeRemote();
        try {
            ICancellationSignal remoteCancellationSignal = null;
            if (cancellationSignal != null) {
                cancellationSignal.throwIfCanceled();
                remoteCancellationSignal = mContentProvider.createCancellationSignal();
                cancellationSignal.setRemote(remoteCancellationSignal);
            }
        try {
            return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
                    sortOrder, remoteCancellationSignal);
        } catch (DeadObjectException e) {
@@ -89,11 +132,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#getType ContentProvider.getType} */
    public String getType(Uri url) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.getType(url);
        } catch (DeadObjectException e) {
@@ -101,11 +147,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#getStreamTypes ContentProvider.getStreamTypes} */
    public String[] getStreamTypes(Uri url, String mimeTypeFilter) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.getStreamTypes(url, mimeTypeFilter);
        } catch (DeadObjectException e) {
@@ -113,11 +162,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#canonicalize} */
    public final Uri canonicalize(Uri url) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.canonicalize(mPackageName, url);
        } catch (DeadObjectException e) {
@@ -125,11 +177,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#uncanonicalize} */
    public final Uri uncanonicalize(Uri url) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.uncanonicalize(mPackageName, url);
        } catch (DeadObjectException e) {
@@ -137,12 +192,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#insert ContentProvider.insert} */
    public Uri insert(Uri url, ContentValues initialValues)
            throws RemoteException {
    public Uri insert(Uri url, ContentValues initialValues) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.insert(mPackageName, url, initialValues);
        } catch (DeadObjectException e) {
@@ -150,11 +207,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#bulkInsert ContentProvider.bulkInsert} */
    public int bulkInsert(Uri url, ContentValues[] initialValues) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.bulkInsert(mPackageName, url, initialValues);
        } catch (DeadObjectException e) {
@@ -162,12 +222,15 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#delete ContentProvider.delete} */
    public int delete(Uri url, String selection, String[] selectionArgs)
            throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.delete(mPackageName, url, selection, selectionArgs);
        } catch (DeadObjectException e) {
@@ -175,12 +238,15 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#update ContentProvider.update} */
    public int update(Uri url, ContentValues values, String selection,
            String[] selectionArgs) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.update(mPackageName, url, values, selection, selectionArgs);
        } catch (DeadObjectException e) {
@@ -188,6 +254,8 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

@@ -212,19 +280,22 @@ public class ContentProviderClient {
     */
    public ParcelFileDescriptor openFile(Uri url, String mode, CancellationSignal signal)
            throws RemoteException, FileNotFoundException {
        beforeRemote();
        try {
            ICancellationSignal remoteSignal = null;
            if (signal != null) {
                signal.throwIfCanceled();
                remoteSignal = mContentProvider.createCancellationSignal();
                signal.setRemote(remoteSignal);
            }
        try {
            return mContentProvider.openFile(mPackageName, url, mode, remoteSignal);
        } catch (DeadObjectException e) {
            if (!mStable) {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

@@ -249,19 +320,22 @@ public class ContentProviderClient {
     */
    public AssetFileDescriptor openAssetFile(Uri url, String mode, CancellationSignal signal)
            throws RemoteException, FileNotFoundException {
        beforeRemote();
        try {
            ICancellationSignal remoteSignal = null;
            if (signal != null) {
                signal.throwIfCanceled();
                remoteSignal = mContentProvider.createCancellationSignal();
                signal.setRemote(remoteSignal);
            }
        try {
            return mContentProvider.openAssetFile(mPackageName, url, mode, remoteSignal);
        } catch (DeadObjectException e) {
            if (!mStable) {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

@@ -275,13 +349,14 @@ public class ContentProviderClient {
    public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
            String mimeType, Bundle opts, CancellationSignal signal)
            throws RemoteException, FileNotFoundException {
        beforeRemote();
        try {
            ICancellationSignal remoteSignal = null;
            if (signal != null) {
                signal.throwIfCanceled();
                remoteSignal = mContentProvider.createCancellationSignal();
                signal.setRemote(remoteSignal);
            }
        try {
            return mContentProvider.openTypedAssetFile(
                    mPackageName, uri, mimeType, opts, remoteSignal);
        } catch (DeadObjectException e) {
@@ -289,12 +364,15 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#applyBatch ContentProvider.applyBatch} */
    public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
            throws RemoteException, OperationApplicationException {
        beforeRemote();
        try {
            return mContentProvider.applyBatch(mPackageName, operations);
        } catch (DeadObjectException e) {
@@ -302,12 +380,14 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

    /** See {@link ContentProvider#call(String, String, Bundle)} */
    public Bundle call(String method, String arg, Bundle extras)
            throws RemoteException {
    public Bundle call(String method, String arg, Bundle extras) throws RemoteException {
        beforeRemote();
        try {
            return mContentProvider.call(mPackageName, method, arg, extras);
        } catch (DeadObjectException e) {
@@ -315,6 +395,8 @@ public class ContentProviderClient {
                mContentResolver.unstableProviderDied(mContentProvider);
            }
            throw e;
        } finally {
            afterRemote();
        }
    }

@@ -359,7 +441,7 @@ public class ContentProviderClient {
    }

    /** {@hide} */
    public static void closeQuietly(ContentProviderClient client) {
    public static void releaseQuietly(ContentProviderClient client) {
        if (client != null) {
            try {
                client.release();
@@ -367,4 +449,12 @@ public class ContentProviderClient {
            }
        }
    }

    private class NotRespondingRunnable implements Runnable {
        @Override
        public void run() {
            Log.w(TAG, "Detected provider not responding: " + mContentProvider);
            mContentResolver.appNotRespondingViaProvider(mContentProvider);
        }
    }
}
Loading