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

Unverified Commit d18c6c18 authored by Marvin W.'s avatar Marvin W. 🐿️
Browse files

Location: Forward more information from fused provider

parent 5ed17740
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@

package org.microg.gms.location.provider

import android.annotation.SuppressLint
import android.app.PendingIntent
import android.content.Intent
import android.location.Criteria
@@ -24,23 +25,29 @@ import kotlin.math.max
class FusedLocationProviderService : IntentLocationProviderService() {
    override fun extractLocation(intent: Intent): Location? = LocationResult.extractResult(intent)?.lastLocation

    @SuppressLint("MissingPermission")
    override fun requestIntentUpdated(currentRequest: ProviderRequestUnbundled?, pendingIntent: PendingIntent) {
        val intervalMillis = max(currentRequest?.interval ?: Long.MAX_VALUE, minIntervalMillis)
        val request = LocationRequest.Builder(intervalMillis)
        if (SDK_INT >= 31 && currentRequest != null) {
            request.setPriority(when {
                currentRequest.interval == LocationRequestCompat.PASSIVE_INTERVAL -> Priority.PRIORITY_PASSIVE
                currentRequest.isLowPower -> Priority.PRIORITY_LOW_POWER
                currentRequest.quality == LocationRequestCompat.QUALITY_LOW_POWER -> Priority.PRIORITY_LOW_POWER
                currentRequest.quality == LocationRequestCompat.QUALITY_HIGH_ACCURACY -> Priority.PRIORITY_HIGH_ACCURACY
                else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY
            })
            request.setMaxUpdateDelayMillis(currentRequest.maxUpdateDelayMillis)
            request.setWorkSource(currentRequest.workSource)
        } else {
            request.setPriority(when {
                currentRequest?.interval == LocationRequestCompat.PASSIVE_INTERVAL -> Priority.PRIORITY_PASSIVE
                else -> Priority.PRIORITY_BALANCED_POWER_ACCURACY
            })
        }
        if (SDK_INT >= 29 && currentRequest != null) {
            request.setBypass(currentRequest.isLocationSettingsIgnored)
        }
        val identity = Binder.clearCallingIdentity()
        try {
            LocationServices.getFusedLocationProviderClient(this).requestLocationUpdates(request.build(), pendingIntent)
+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ class IntentLocationProviderPreTiramisu : AbstractLocationProviderPreTiramisu {
    override fun dump(writer: PrintWriter) {
        writer.println("Enabled: $enabled")
        writer.println("Current request: $currentRequest")
        if (SDK_INT >= 31) writer.println("Current work source: ${currentRequest?.workSource}")
        writer.println("Last reported: $lastReportedLocation")
        writer.println("Last report time: ${lastReportTime.formatRealtime()}")
    }
+2 −2
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life
        }
        val permissionGranularity = context.granularityFromPermission(clientIdentity)
        var effectiveGranularity = getEffectiveGranularity(request.granularity, permissionGranularity)
        if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(clientIdentity.packageName)) effectiveGranularity = GRANULARITY_COARSE
        if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE
        val returnedLocation = if (effectiveGranularity > permissionGranularity) {
            // No last location available at requested granularity due to lack of permission
            null
@@ -98,7 +98,7 @@ class LocationManager(private val context: Context, override val lifecycle: Life
                processedLocation
            }
        }
        database.noteAppLocation(clientIdentity.packageName, returnedLocation)
        if (!clientIdentity.isSelfUser()) database.noteAppLocation(clientIdentity.packageName, returnedLocation)
        return returnedLocation?.let { Location(it).apply { provider = "fused" } }
    }

+6 −6
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ class LocationRequestManager(private val context: Context, override val lifecycl
            try {
                val startedHolder = holder?.update(callback, request) ?: LocationRequestHolder(context, clientIdentity, request, callback, null).start().also {
                    var effectiveGranularity = it.effectiveGranularity
                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName)) effectiveGranularity = GRANULARITY_COARSE
                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE
                    val lastLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis)
                    if (lastLocation != null) it.processNewLocation(lastLocation)
                }
@@ -121,7 +121,7 @@ class LocationRequestManager(private val context: Context, override val lifecycl
                pendingIntentRequests[pendingIntent] = LocationRequestHolder(context, clientIdentity, request, null, pendingIntent).start().also {
                    cacheManager.add(it.asParcelable()) { it.pendingIntent == pendingIntent }
                    var effectiveGranularity = it.effectiveGranularity
                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName)) effectiveGranularity = GRANULARITY_COARSE
                    if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(it.clientIdentity.packageName) && !clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE
                    val lastLocation = lastLocationCapsule.getLocation(effectiveGranularity, request.maxUpdateAgeMillis)
                    if (lastLocation != null) it.processNewLocation(lastLocation)
                }
@@ -147,11 +147,11 @@ class LocationRequestManager(private val context: Context, override val lifecycl
        for ((key, holder) in map) {
            try {
                var effectiveGranularity = holder.effectiveGranularity
                if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(holder.clientIdentity.packageName)) effectiveGranularity = GRANULARITY_COARSE
                if (effectiveGranularity == GRANULARITY_FINE && database.getForceCoarse(holder.clientIdentity.packageName) && !holder.clientIdentity.isSelfUser()) effectiveGranularity = GRANULARITY_COARSE
                val location = lastLocationCapsule.getLocation(effectiveGranularity, holder.maxUpdateDelayMillis)
                postProcessor.process(location, effectiveGranularity, holder.clientIdentity.isGoogle(context))?.let {
                    if (holder.processNewLocation(it)) {
                        database.noteAppLocation(holder.clientIdentity.packageName, it)
                        if (!holder.clientIdentity.isSelfUser()) database.noteAppLocation(holder.clientIdentity.packageName, it)
                        updated.add(key)
                    }
                }
@@ -420,7 +420,7 @@ class LocationRequestManager(private val context: Context, override val lifecycl
                get() = request.maxUpdates - updates
            val timePendingMillis: Long
                get() = request.durationMillis - (SystemClock.elapsedRealtime() - start)
            var workSource: WorkSource = WorkSource(request.workSource).also { WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
            var workSource: WorkSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
                private set
            val effectiveHighPower: Boolean
                get() = request.intervalMillis < 60000 || effectivePriority == PRIORITY_HIGH_ACCURACY
@@ -431,7 +431,7 @@ class LocationRequestManager(private val context: Context, override val lifecycl
                this.request = request
                this.start = SystemClock.elapsedRealtime()
                this.updates = 0
                this.workSource = WorkSource(request.workSource).also { WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
                this.workSource = WorkSource(request.workSource).also { if (!clientIdentity.isSelfUser()) WorkSourceUtil.add(it, clientIdentity.uid, clientIdentity.packageName) }
                if (changedGranularity) {
                    if (!context.checkAppOpForEffectiveGranularity(clientIdentity, effectiveGranularity)) throw RuntimeException("Lack of permission")
                }
+3 −2
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ fun ILocationCallback.redirectCancel(fusedCallback: IFusedLocationProviderCallba
fun ClientIdentity.isGoogle(context: Context) = PackageUtils.isGooglePackage(context, packageName)

fun ClientIdentity.isSelfProcess() = pid == Process.myPid()
fun ClientIdentity.isSelfUser() = uid == Process.myUid()

fun Context.granularityFromPermission(clientIdentity: ClientIdentity): @Granularity Int = when (PackageManager.PERMISSION_GRANTED) {
    packageManager.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, clientIdentity.packageName) -> Granularity.GRANULARITY_FINE
@@ -77,13 +78,13 @@ fun Context.granularityFromPermission(clientIdentity: ClientIdentity): @Granular

fun LocationRequest.verify(context: Context, clientIdentity: ClientIdentity) {
    GranularityUtil.checkValidGranularity(granularity)
    if (isBypass) {
    if (isBypass && !clientIdentity.isSelfUser()) {
        val permission = if (SDK_INT >= 33) "android.permission.LOCATION_BYPASS" else Manifest.permission.WRITE_SECURE_SETTINGS
        if (context.checkPermission(permission, clientIdentity.pid, clientIdentity.uid) != PackageManager.PERMISSION_GRANTED) {
            throw SecurityException("Caller must hold $permission for location bypass")
        }
    }
    if (impersonation != null) {
    if (impersonation != null && !clientIdentity.isSelfUser()) {
        Log.w(TAG, "${clientIdentity.packageName} wants to impersonate ${impersonation!!.packageName}. Ignoring.")
    }