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

Commit 39275e7d authored by Yu-Han Yang's avatar Yu-Han Yang
Browse files

Update isInEmergency without holding a lock

Bug: 355384257
Test: on device
Flag: android.location.flags.update_is_in_emergency_before_on_register
Change-Id: Ice18045a4a0346a357ad1ecc0800b7189481563a
parent ba55b9ac
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -166,6 +166,16 @@ flag {
    }
}

flag {
    name: "update_is_in_emergency_before_on_register"
    namespace: "location"
    description: "Update isInEmergency before onRegister() without holding a lock"
    bug: "355384257"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "gnss_assistance_interface_jni"
    namespace: "location"
+42 −25
Original line number Diff line number Diff line
@@ -395,6 +395,9 @@ public class LocationProviderManager extends
        @GuardedBy("mMultiplexerLock")
        private boolean mIsUsingHighPower;

        @GuardedBy("mMultiplexerLock")
        private boolean mIsInEmergency;

        @Nullable private Location mLastLocation = null;

        protected Registration(LocationRequest request, CallerIdentity identity, Executor executor,
@@ -421,6 +424,24 @@ public class LocationProviderManager extends
            }
        }

        /** Update {@link #mIsInEmergency} by invoking Telephony APIs. **/
        public void updateIsInEmergency() {
            boolean isInEmergency = mEmergencyHelper.isInEmergency(0);
            synchronized (mMultiplexerLock) {
                mIsInEmergency = isInEmergency;
            }
        }

        /**
         * Make sure to call {@link #updateIsInEmergency()} before calling this method to keep
         * {@link #mIsInEmergency} up-to-date.
         *
         * <p>See b/426562854 for more details. {@link #updateIsInEmergency()} is a short term
         * solution to avoid calling IPC with a lock by caching the state right before onRegister().
         * The long term solution should be avoiding any synchronous
         * {@link EmergencyHelper#isInEmergency()}} and using the asynchronous emergency listeners
         * instead.
         */
        @GuardedBy("mMultiplexerLock")
        @Override
        protected void onRegister() {
@@ -435,7 +456,11 @@ public class LocationProviderManager extends

            // initialization order is important as there are ordering dependencies
            onLocationPermissionsChanged();
            if (Flags.updateIsInEmergencyBeforeOnRegister()) {
                onBypassLocationPermissionsChanged(mIsInEmergency);
            } else {
                onBypassLocationPermissionsChanged(mEmergencyHelper.isInEmergency(0));
            }
            mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
            mProviderLocationRequest = calculateProviderLocationRequest();
            mIsUsingHighPower = isUsingHighPower();
@@ -1991,20 +2016,12 @@ public class LocationProviderManager extends
                        identity,
                        new GetCurrentLocationTransport(callback),
                        permissionLevel);

        synchronized (mMultiplexerLock) {
            Preconditions.checkState(mState != STATE_STOPPED);
            final long ident = Binder.clearCallingIdentity();
            try {
                putRegistration(callback.asBinder(), registration);
        registerAndHandleIdentity(callback.asBinder(), registration, () -> {
            if (!registration.isActive()) {
                // if the registration never activated, fail it immediately
                registration.deliverNull();
            }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
        });

        ICancellationSignal cancelTransport = CancellationSignal.createTransport();
        CancellationSignal.fromTransport(cancelTransport)
@@ -2045,16 +2062,7 @@ public class LocationProviderManager extends
                identity,
                new LocationListenerTransport(listener),
                permissionLevel);

        synchronized (mMultiplexerLock) {
            Preconditions.checkState(mState != STATE_STOPPED);
            final long ident = Binder.clearCallingIdentity();
            try {
                putRegistration(listener.asBinder(), registration);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
        registerAndHandleIdentity(listener.asBinder(), registration, () -> {});
    }

    public void registerLocationRequest(LocationRequest request, CallerIdentity callerIdentity,
@@ -2064,12 +2072,21 @@ public class LocationProviderManager extends
                callerIdentity,
                new LocationPendingIntentTransport(mContext, pendingIntent),
                permissionLevel);
        registerAndHandleIdentity(pendingIntent, registration, () -> {});
    }

    private <T> void registerAndHandleIdentity(T key, Registration registration,
                                               Runnable postRegistrationRunnable) {
        if (Flags.updateIsInEmergencyBeforeOnRegister()) {
            registration.updateIsInEmergency();
        }

        synchronized (mMultiplexerLock) {
            Preconditions.checkState(mState != STATE_STOPPED);
            final long identity = Binder.clearCallingIdentity();
            try {
                putRegistration(pendingIntent, registration);
                putRegistration(key, registration);
                postRegistrationRunnable.run();
            } finally {
                Binder.restoreCallingIdentity(identity);
            }