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

Commit f591b76a authored by Varun Shah's avatar Varun Shah
Browse files

Locking and performance improvements in Content Provider.

Freeing up a couple of methods which required the AMS lock. Also some
performance improvements to address certain bottlenecks.

Also minor code refactoring.

Bug: 156262145
Test: atest ContentProviderTest [all]
Change-Id: I3092a58aa7debbd7e0bef531c05e3ce8f39d3a14
parent 5117501a
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -17480,8 +17480,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        @Override
        public int checkContentProviderUriPermission(Uri uri, int userId,
                int callingUid, int modeFlags) {
            return mCpHelper.checkContentProviderUriPermission(uri,
                    userId, callingUid, modeFlags);
            return mCpHelper.checkContentProviderUriPermission(uri, userId, callingUid, modeFlags);
        }
        @Override
+65 −70
Original line number Diff line number Diff line
@@ -197,22 +197,10 @@ public class ContentProviderHelper {

            if (providerRunning) {
                cpi = cpr.info;
                String msg;

                if (r != null && cpr.canRunHere(r)) {
                    if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
                        throw new SecurityException("Content provider lookup "
                                + cpr.name.flattenToShortString()
                                + " failed: association not allowed with package " + msg);
                    }
                    checkTime(startTime,
                            "getContentProviderImpl: before checkContentProviderPermission");
                    if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
                            != null) {
                        throw new SecurityException(msg);
                    }
                    checkTime(startTime,
                            "getContentProviderImpl: after checkContentProviderPermission");
                    checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
                            cpr.name.flattenToShortString(), startTime);

                    // This provider has been published or is in the process
                    // of being published...  but it is also allowed to run
@@ -233,26 +221,14 @@ public class ContentProviderHelper {
                } catch (RemoteException e) {
                }

                if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
                    throw new SecurityException(
                            "Content provider lookup " + cpr.name.flattenToShortString()
                                    + " failed: association not allowed with package " + msg);
                }
                checkTime(startTime,
                        "getContentProviderImpl: before checkContentProviderPermission");
                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
                        != null) {
                    throw new SecurityException(msg);
                }
                checkTime(startTime,
                        "getContentProviderImpl: after checkContentProviderPermission");
                checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
                        cpr.name.flattenToShortString(), startTime);

                final long origId = Binder.clearCallingIdentity();

                checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");

                // In this case the provider instance already exists, so we can
                // return it right away.
                // In this case the provider instance already exists so we can return it right away.
                conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
                        stable, true, startTime, mService.mProcessList);

@@ -327,19 +303,8 @@ public class ContentProviderHelper {
                cpi.applicationInfo = mService.getAppInfoForUser(cpi.applicationInfo, userId);
                checkTime(startTime, "getContentProviderImpl: got app info for user");

                String msg;
                if ((msg = checkContentProviderAssociation(r, callingUid, cpi)) != null) {
                    throw new SecurityException("Content provider lookup " + name
                            + " failed: association not allowed with package " + msg);
                }
                checkTime(startTime,
                        "getContentProviderImpl: before checkContentProviderPermission");
                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                        != null) {
                    throw new SecurityException(msg);
                }
                checkTime(startTime,
                        "getContentProviderImpl: after checkContentProviderPermission");
                checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, !singleton,
                        name, startTime);

                if (!mService.mProcessesReady && !cpi.processName.equals("system")) {
                    // If this content provider does not run in the system
@@ -351,11 +316,13 @@ public class ContentProviderHelper {

                // If system providers are not installed yet we aggressively crash to avoid
                // creating multiple instance of these providers and then bad things happen!
                synchronized (this) {
                    if (!mSystemProvidersInstalled && cpi.applicationInfo.isSystemApp()
                            && "system".equals(cpi.processName)) {
                        throw new IllegalStateException("Cannot access system provider: '"
                                + cpi.authority + "' before system providers are installed!");
                    }
                }

                // Make sure that the user who owns this provider is running.  If not,
                // we don't want to allow it to run.
@@ -572,6 +539,23 @@ public class ContentProviderHelper {
        return cpr.newHolder(conn);
    }

    private void checkAssociationAndPermissionLocked(ProcessRecord callingApp, ProviderInfo cpi,
            int callingUid, int userId, boolean checkUser, String cprName, long startTime) {
        String msg;
        if ((msg = checkContentProviderAssociation(callingApp, callingUid, cpi)) != null) {
            throw new SecurityException("Content provider lookup " + cprName
                    + " failed: association not allowed with package " + msg);
        }
        checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
        if ((msg = checkContentProviderPermission(
                    cpi, Binder.getCallingPid(), Binder.getCallingUid(), userId, checkUser,
                    callingApp != null ? callingApp.toString() : null))
                != null) {
            throw new SecurityException(msg);
        }
        checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
    }

    void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
        if (providers == null) {
            return;
@@ -590,7 +574,7 @@ public class ContentProviderHelper {
            }

            final long origId = Binder.clearCallingIdentity();

            boolean providersPublished = false;
            for (int i = 0, size = providers.size(); i < size; i++) {
                ContentProviderHolder src = providers.get(i);
                if (src == null || src.info == null || src.provider == null) {
@@ -603,6 +587,7 @@ public class ContentProviderHelper {
                if (DEBUG_MU) {
                    Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
                }
                providersPublished = true;

                ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                mProviderMap.putProviderByClass(comp, dst);
@@ -637,8 +622,19 @@ public class ContentProviderHelper {
                    dst.notifyAll();
                }
                dst.mRestartCount = 0;
            }

            // update the app's oom adj value and each provider's usage stats
            if (providersPublished) {
                mService.updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                maybeUpdateProviderUsageStatsLocked(r, src.info.packageName, src.info.authority);
                for (int i = 0, size = providers.size(); i < size; i++) {
                    ContentProviderHolder src = providers.get(i);
                    if (src == null || src.info == null || src.provider == null) {
                        continue;
                    }
                    maybeUpdateProviderUsageStatsLocked(r,
                            src.info.packageName, src.info.authority);
                }
            }

            Binder.restoreCallingIdentity(origId);
@@ -961,17 +957,19 @@ public class ContentProviderHelper {
                    + "; expected to find a valid ContentProvider for this authority";
        }

        final int callingPid = Binder.getCallingPid();
        ProcessRecord r;
        final String appName;
        synchronized (mService.mPidsSelfLocked) {
            r = mService.mPidsSelfLocked.get(Binder.getCallingPid());
        }
            r = mService.mPidsSelfLocked.get(callingPid);
            if (r == null) {
            return "Failed to find PID " + Binder.getCallingPid();
                return "Failed to find PID " + callingPid;
            }

        synchronized (mService) {
            return checkContentProviderPermissionLocked(cpi, r, userId, true);
            appName = r.toString();
        }

        return checkContentProviderPermission(cpi, callingPid, Binder.getCallingUid(),
                userId, true, appName);
    }

    int checkContentProviderUriPermission(Uri uri, int userId, int callingUid, int modeFlags) {
@@ -1127,13 +1125,14 @@ public class ContentProviderHelper {
                }
            }
        }

        synchronized (this) {
            if (providers != null) {
                mService.mSystemThread.installSystemProviders(providers);
            }

        synchronized (mService) {
            mSystemProvidersInstalled = true;
        }

        mService.mConstants.start(mService.mContext.getContentResolver());
        mService.mCoreSettingsObserver = new CoreSettingsObserver(mService);
        mService.mActivityTaskManager.installSystemProviders();
@@ -1269,10 +1268,8 @@ public class ContentProviderHelper {
     * given {@link ProviderInfo}. Final permission checking is always done
     * in {@link ContentProvider}.
     */
    private String checkContentProviderPermissionLocked(ProviderInfo cpi, ProcessRecord r,
            int userId, boolean checkUser) {
        final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
        final int callingUid = (r != null) ? r.uid : Binder.getCallingUid();
    private String checkContentProviderPermission(ProviderInfo cpi, int callingPid, int callingUid,
            int userId, boolean checkUser, String appName) {
        boolean checkedGrants = false;
        if (checkUser) {
            // Looking for cross-user grants before enforcing the typical cross-users permissions
@@ -1340,8 +1337,8 @@ public class ContentProviderHelper {
            suffix = " requires " + cpi.readPermission + " or " + cpi.writePermission;
        }
        final String msg = "Permission Denial: opening provider " + cpi.name
                + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
                + ", uid=" + callingUid + ")" + suffix;
                + " from " + (appName != null ? appName : "(null)")
                + " (pid=" + callingPid + ", uid=" + callingUid + ")" + suffix;
        Slog.w(TAG, msg);
        return msg;
    }
@@ -1362,18 +1359,17 @@ public class ContentProviderHelper {
    }

    ProviderInfo getProviderInfoLocked(String authority, @UserIdInt int userId, int pmFlags) {
        ProviderInfo pi = null;
        ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId);
        if (cpr != null) {
            pi = cpr.info;
            return cpr.info;
        } else {
            try {
                pi = AppGlobals.getPackageManager().resolveContentProvider(
                return AppGlobals.getPackageManager().resolveContentProvider(
                        authority, PackageManager.GET_URI_PERMISSION_PATTERNS | pmFlags, userId);
            } catch (RemoteException ex) {
                return null;
            }
        }
        return pi;
    }

    private void maybeUpdateProviderUsageStatsLocked(ProcessRecord app, String providerPkgName,
@@ -1383,7 +1379,6 @@ public class ContentProviderHelper {
            return;
        }


        UserState userState = mService.mUserController.getStartedUserState(app.userId);
        if (userState == null) return;
        final long now = SystemClock.elapsedRealtime();