Android T GPS 定位流程

Android T 的 location 代码都整到一起了,看上去有序些,但代码梳理起来感觉太细了,整体代码目录结构如下:
在这里插入图片描述
再看下之前介绍的Android P 上的目录:
在这里插入图片描述
这里我们还是按照先Gps定位,后网络的顺序梳理下流程。还是一样的套路,通过LocationManager提供的API接口往下梳理:
frameworks/base/location/java/android/location/LocationManager.java
在这里插入图片描述
继续看流程:/frameworks/base/services/core/java/com/android/server/location/LocationManagerService.java

public void registerLocationListener(String provider, LocationRequest request,
        ILocationListener listener, String packageName, @Nullable String attributionTag,  String listenerId) {
    // packageName 请求者报名
    // request   封装的请求参数
    // provider  请求的哪个Provide
    CallerIdentity identity = CallerIdentity.fromBinder(mContext, packageName, attributionTag, listenerId);
    // check 权限是不是被授予
    int permissionLevel = LocationPermissions.getPermissionLevel(mContext, identity.getUid(), identity.getPid()); 
    LocationPermissions.enforceLocationPermission(identity.getUid(), permissionLevel, PERMISSION_COARSE);

    // clients in the system process should have an attribution tag set
    if (identity.getPid() == Process.myPid() && attributionTag == null) {
        Log.w(TAG, "system location request with no attribution tag", new IllegalArgumentException());
    }

    request = validateLocationRequest(provider, request, identity);
	
	// 检查该Provide是否存在,存在就调用registerLocationRequest
    LocationProviderManager manager = getLocationProviderManager(provider);
    Preconditions.checkArgument(manager != null, "provider \"" + provider + "\" does not exist");

    manager.registerLocationRequest(request, identity, permissionLevel, listener);
}

继续看流程:frameworks/base/services/core/java/com/android/server/location/provider/LocationProviderManager.java

public void registerLocationRequest(LocationRequest request, CallerIdentity identity,
        @PermissionLevel int permissionLevel, ILocationListener listener) {
     
    //封装成 LocationListenerRegistration 
    LocationListenerRegistration registration = new LocationListenerRegistration(
            request,
            identity,
            new LocationListenerTransport(listener),
            permissionLevel);

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

protected final class LocationListenerRegistration extends LocationRegistration implements IBinder.DeathRecipient {
   LocationListenerRegistration(LocationRequest request, CallerIdentity identity,
           LocationListenerTransport transport, @PermissionLevel int permissionLevel) {
       super(request, identity, transport, permissionLevel);   ---> 父类的
   }

protected abstract class LocationRegistration extends Registration implements
        OnAlarmListener, ProviderEnabledListener {
        protected <TTransport extends LocationTransport & ProviderTransport> LocationRegistration(
                LocationRequest request, CallerIdentity identity, TTransport transport,
                @PermissionLevel int permissionLevel) {
            super(request, identity, transport, permissionLevel);  ---> 父类的
            mProviderTransport = transport;
            mWakeLock = Objects.requireNonNull(mContext.getSystemService(PowerManager.class))
                    .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
            mWakeLock.setReferenceCounted(true);
            mWakeLock.setWorkSource(request.getWorkSource());
            mWakeLockReleaser = new ExternalWakeLockReleaser(identity, mWakeLock);
        }

protected abstract class Registration extends RemoteListenerRegistration<LocationRequest,
            LocationTransport> {
      protected Registration(LocationRequest request, CallerIdentity identity,
                LocationTransport transport, @PermissionLevel int permissionLevel) {
            super(Objects.requireNonNull(request), identity, transport);  ---> 父类的

            Preconditions.checkArgument(identity.getListenerId() != null);
            Preconditions.checkArgument(permissionLevel > PERMISSION_NONE);
            Preconditions.checkArgument(!request.getWorkSource().isEmpty());

            mPermissionLevel = permissionLevel;
            mProviderLocationRequest = request;
        }
        
 public abstract class RemoteListenerRegistration<TRequest, TListener> extends
        RemovableListenerRegistration<TRequest, TListener> {
	protected RemoteListenerRegistration(@Nullable TRequest request, CallerIdentity identity, TListener listener) {
        super(chooseExecutor(identity), request, listener);  ---> 父类的
        mIdentity = Objects.requireNonNull(identity);
    }

public abstract class RemovableListenerRegistration<TRequest, TListener> extends
        RequestListenerRegistration<TRequest, TListener> {
    protected RemovableListenerRegistration(Executor executor, @Nullable TRequest request,
            TListener listener) {
        super(executor, request, listener);  ---> 父类的
    }
 
public class RequestListenerRegistration<TRequest, TListener> extends
        ListenerRegistration<TListener> {
    protected RequestListenerRegistration(Executor executor, TRequest request,
            TListener listener) {
        super(executor, listener);  ---> 父类的
        mRequest = request;
    }
   
 public class ListenerRegistration<TListener> implements ListenerExecutor {
    protected ListenerRegistration(Executor executor, TListener listener) {
        mExecutor = Objects.requireNonNull(executor);
        mActive = false;
        mListener = Objects.requireNonNull(listener);
    }

这里只是 new LocationListenerRegistration,结果牵扯出这么多,都看晕了,不知道为啥谷歌搞得这么多
在这里插入图片描述
然后在执行: putRegistration(listener.asBinder(), registration);
代码位置:frameworks/base/services/core/java/com/android/server/location/listeners/ListenerMultiplexer.java

protected final void putRegistration(@NonNull TKey key, @NonNull TRegistration registration) {
    replaceRegistration(key, key, registration);
}

// 注意参数,oldKey和key是同一个key
protected final void replaceRegistration(@NonNull TKey oldKey, @NonNull TKey key,
        @NonNull TRegistration registration) {
    Objects.requireNonNull(oldKey);
    Objects.requireNonNull(key);
    Objects.requireNonNull(registration);

    synchronized (mRegistrations) {
        // adding listeners reentrantly is not supported
        Preconditions.checkState(!mReentrancyGuard.isReentrant());

        // new key may only have a prior registration if the oldKey is the same as the key
        Preconditions.checkArgument(oldKey == key || !mRegistrations.containsKey(key));

        // since adding a registration can invoke a variety of callbacks, we need to ensure
        // those callbacks themselves do not re-enter, as this could lead to out-of-order
        // callbacks. further, we buffer service updates since adding a registration may
        // involve removing a prior registration. note that try-with-resources ordering is
        // meaningful here as well. we want to close the reentrancy guard first, as this may
        // generate additional service updates, then close the update service buffer.
        try (UpdateServiceBuffer ignored1 = mUpdateServiceBuffer.acquire();
             ReentrancyGuard ignored2 = mReentrancyGuard.acquire()) {

            boolean wasEmpty = mRegistrations.isEmpty();
            TRegistration oldRegistration = null;
            int index = mRegistrations.indexOfKey(oldKey);   ---> 第一次里面找不到
            if (index >= 0) {
                oldRegistration = removeRegistration(index, oldKey != key);
            }
            if (oldKey == key && index >= 0) {
                mRegistrations.setValueAt(index, registration);
            } else {
                mRegistrations.put(key, registration);    ---> ArrayMap<TKey, TRegistration> mRegistrations = new ArrayMap<>()
            }

            if (wasEmpty) {   ---> 上面判断了,第一次肯定是空的
                onRegister();   ---> 这个又调回 LocationProviderManager#onRegister()方法
            }
            registration.onRegister(key);
            if (oldRegistration == null) {
                onRegistrationAdded(key, registration);
            } else {
                onRegistrationReplaced(key, oldRegistration, registration);
            }
            onRegistrationActiveChanged(registration);
        }
    }
}

// LocationProviderManager#onRegister()方法,注册这些listen
protected void onRegister() {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }

    mSettingsHelper.addOnBackgroundThrottleIntervalChangedListener(mBackgroundThrottleIntervalChangedListener);
    mSettingsHelper.addOnBackgroundThrottlePackageWhitelistChangedListener(mBackgroundThrottlePackageWhitelistChangedListener);
    mSettingsHelper.addOnLocationPackageBlacklistChangedListener(mLocationPackageBlacklistChangedListener);
    mSettingsHelper.addAdasAllowlistChangedListener(mAdasPackageAllowlistChangedListener);
    mSettingsHelper.addIgnoreSettingsAllowlistChangedListener(mIgnoreSettingsPackageWhitelistChangedListener);
    mLocationPermissionsHelper.addListener(mLocationPermissionsListener);
    mAppForegroundHelper.addListener(mAppForegroundChangedListener);
    mLocationPowerSaveModeHelper.addListener(mLocationPowerSaveModeChangedListener);
    mScreenInteractiveHelper.addListener(mScreenInteractiveChangedListener);
}

再继续会看剩下的逻辑 registration.onRegister(key) 又是调用哪个?
在这里插入图片描述
调用的是 RemovableListenerRegistration#onRegister(Object key) —> LocationProviderManager#onRemovableListenerRegister()
看下代码:frameworks/base/services/core/java/com/android/server/location/provider/LocationProviderManager.java

protected final void onRemovableListenerRegister() {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }
	// name 指的是 Provide
	// getIdentity 指的是 PID 包名之类的
	// getRequest 就是request封装的一些参数
    Log.d(TAG, mName + " provider added registration from " + getIdentity() + " -> "  + getRequest());

    EVENT_LOG.logProviderClientRegistered(mName, getIdentity(), super.getRequest());

    // initialization order is important as there are ordering dependencies
    mPermitted = mLocationPermissionsHelper.hasLocationPermissions(mPermissionLevel,  getIdentity());
    mForeground = mAppForegroundHelper.isAppForeground(getIdentity().getUid());
    mProviderLocationRequest = calculateProviderLocationRequest();
    mIsUsingHighPower = isUsingHighPower();

    onProviderListenerRegister();

    if (mForeground) {
        EVENT_LOG.logProviderClientForeground(mName, getIdentity());
    }
}

// 再看下 onProviderListenerRegister 方法:
protected final void onProviderListenerRegister() {
    long registerTimeMs = SystemClock.elapsedRealtime();
    mExpirationRealtimeMs = getRequest().getExpirationRealtimeMs(registerTimeMs);

    // add alarm for expiration
    if (mExpirationRealtimeMs <= registerTimeMs) {
        onAlarm();
    } else if (mExpirationRealtimeMs < Long.MAX_VALUE) {
        // Set WorkSource to null in order to ensure the alarm wakes up the device even when
        // it is idle. Do this when the cost of waking up the device is less than the power
        // cost of not performing the actions set off by the alarm, such as unregistering a
        // location request.
        mAlarmHelper.setDelayedAlarm(mExpirationRealtimeMs - registerTimeMs, this, null);
    }

    // start listening for provider enabled/disabled events
    addEnabledListener(this);
    onLocationListenerRegister();

    // if the provider is currently disabled, let the client know immediately
    int userId = getIdentity().getUserId();   ---> 多用户,一般是0
    if (!isEnabled(userId)) {
        onProviderEnabledChanged(mName, userId, false);
    }
}

// 如果Provide没有使能就调用 deliverOnProviderEnabledChanged 通知注册的listen 
public void onProviderEnabledChanged(String provider, int userId, boolean enabled) {
    Preconditions.checkState(mName.equals(provider));

    if (userId != getIdentity().getUserId()) {
        return;
    }

    // we choose not to hold a wakelock for provider enabled changed events
    executeSafely(getExecutor(), () -> mProviderTransport,
            listener -> listener.deliverOnProviderEnabledChanged(mName, enabled),
            this::onProviderOperationFailure);
}

registration.onRegister(key) 看完了,再继续往下看,再回到上面那个图,很明显首次oldRegistration是null,所以就执行: onRegistrationAdded(key, registration),就跳到去执行: LocationProviderManager#onRegistrationAdded(具体的可以看下代码,就是把这些记录到statsd中,statsd是后台运行的原生服务,用于收集指标这些)
在这里插入图片描述
OK,再往下看,接着就执行: onRegistrationActiveChanged(registration);

private void onRegistrationActiveChanged(TRegistration registration) {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mRegistrations));
    }
	// 这两个判断条件很重要,前者是是否注册,后者是否活跃
    boolean active = registration.isRegistered() && isActive(registration);  ---> 看下面的isActive() 方法
    boolean changed = registration.setActive(active);   
    // 如果changed 为false,结束
    if (changed) {
        if (active) {
            if (++mActiveRegistrationsCount == 1) {
                onActive();   ---> 下面也贴了这个方法
            }
            registration.onActive();
        } else {
            registration.onInactive();
            if (--mActiveRegistrationsCount == 0) {
                onInactive();
            }
        }
        updateService();
    }
}

// registration.setActive(active) 方法:
final boolean setActive(boolean active) {
    if (active != mActive) {
        mActive = active;
        return true;
    }
    return false;
}

// 看下 isActive() 方法实现:
protected boolean isActive(Registration registration) {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }

    if (!registration.isPermitted()) {
        return false;
    }

    boolean isBypass = registration.getRequest().isBypass();    ---> 这个可以理解为不受限位置的应用或者服务
    if (!isActive(isBypass, registration.getIdentity())) {  ---> 根据这两个参数来判断是不是Active,看下面的分析
        return false;
    }
	// 也就是说想走到下面,必须满足isBypass为false
    if (!isBypass) {
        switch (mLocationPowerSaveModeHelper.getLocationPowerSaveMode()) {
            case LOCATION_MODE_FOREGROUND_ONLY:
                if (!registration.isForeground()) {
                    return false;
                }
                break;
            case LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF:
                if (!GPS_PROVIDER.equals(mName)) {
                    break;
                }
                // fall through
            case LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF:
                // fall through
            case LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF:
                if (!mScreenInteractiveHelper.isInteractive()) {
                    return false;
                }
                break;
            case LOCATION_MODE_NO_CHANGE:
                // fall through
            default:
                break;
        }
    }

    return true;
}

// isActive(isBypass, registration.getIdentity()) 两个参数的方法:
/* 几种情况:
	1. 系统应用,是isBypass的,返回ture
	2. 系统应用,是isBypass的,且Provider已经使能,返回ture
	3. 非系统应用,是isBypass的,然后不在黑名单里面,返回ture
*/
private boolean isActive(boolean isBypass, CallerIdentity identity) {
    if (identity.isSystemServer()) {
        if (!isBypass) {
            if (!isEnabled(mUserHelper.getCurrentUserId())) {
                return false;
            }
        }
    } else {
        if (!isBypass) {
            if (!isEnabled(identity.getUserId())) {
                return false;
            }
            if (!mUserHelper.isCurrentUserId(identity.getUserId())) {
                return false;
            }
        }
        if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
                identity.getPackageName())) {
            return false;
        }
    }
    return true;
}

// onActive() 方法:
protected final void onActive() {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }

    EVENT_LOG.logProviderClientActive(mName, getIdentity());

    if (!getRequest().isHiddenFromAppOps()) {
        mAppOpsHelper.startOpNoThrow(OP_MONITOR_LOCATION, getIdentity());
    }
    onHighPowerUsageChanged();
    onProviderListenerActive();
}

protected final void onProviderListenerActive() {
    // a new registration may not get a location immediately, the provider request may be
    // delayed. therefore we deliver a historical location if available. since delivering an
    // older location could be considered a breaking change for some applications, we only
    // do so for apps targeting S+.
    if (isChangeEnabled(DELIVER_HISTORICAL_LOCATIONS, getIdentity().getUid())) {
        long maxLocationAgeMs = getRequest().getIntervalMillis();
        Location lastDeliveredLocation = getLastDeliveredLocation();
        if (lastDeliveredLocation != null) {
            // ensure that location is fresher than the last delivered location
            maxLocationAgeMs = min(maxLocationAgeMs,
                    lastDeliveredLocation.getElapsedRealtimeAgeMillis() - 1);
        }

        // requests are never delayed less than MIN_REQUEST_DELAY_MS, so it only makes sense
        // to deliver historical locations to clients with a last location older than that
        if (maxLocationAgeMs > MIN_REQUEST_DELAY_MS) {
            Location lastLocation = getLastLocationUnsafe(
                    getIdentity().getUserId(),
                    getPermissionLevel(),
                    getRequest().isBypass(),
                    maxLocationAgeMs);
            if (lastLocation != null) {    ---> 现在没有任何位置信息是不会走这里
                executeOperation(acceptLocationChange(LocationResult.wrap(lastLocation)));
            }
        }
    }
}

OK,首先我没能理解这个 ++mActiveRegistrationsCount == 1,这个条件满足执行onActive()方法,虽然上面也看了这个代码。为了流程先跳过吧,这里吐槽一句,Android T 的location代码谷歌写的真是……
接着再看:updateService()

protected final void updateService() {
    synchronized (mRegistrations) {
        if (mUpdateServiceBuffer.isBuffered()) {
            mUpdateServiceBuffer.markUpdateServiceRequired();
            return;
        }
		// 这个其实就是把现在的 Registrations 遍历一遍,判断是否是isActive
        ArrayList<TRegistration> actives = new ArrayList<>(mRegistrations.size());
        final int size = mRegistrations.size();
        for (int i = 0; i < size; i++) {
            TRegistration registration = mRegistrations.valueAt(i);
            if (registration.isActive()) {  ---> 之前流程是 setActive 过的
                actives.add(registration);
            }
        }

        if (actives.isEmpty()) {
            if (mServiceRegistered) {
                mMerged = null;
                mServiceRegistered = false;
                unregisterWithService();
            }
            return;
        }

        TMergedRegistration merged = mergeRegistrations(actives);   ---> 下面看下这个方法
        if (!mServiceRegistered || !Objects.equals(merged, mMerged)) {
            if (mServiceRegistered) {
                mServiceRegistered = reregisterWithService(mMerged, merged, actives);
            } else {
                mServiceRegistered = registerWithService(merged, actives);   ---> 首次,看这个
            }
            mMerged = mServiceRegistered ? merged : null;
        }
    }
}


// mergeRegistrations(actives),通过合并多个注册并计算功耗归因责任,生成一个合并后的提供者请求对象,该请求包含了合并注册的相关参数信息
protected ProviderRequest mergeRegistrations(Collection<Registration> registrations) {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }

    long intervalMs = ProviderRequest.INTERVAL_DISABLED;
    int quality = LocationRequest.QUALITY_LOW_POWER;
    long maxUpdateDelayMs = Long.MAX_VALUE;
    boolean adasGnssBypass = false;
    boolean locationSettingsIgnored = false;
    boolean lowPower = true;

    for (Registration registration : registrations) {
        LocationRequest request = registration.getRequest();

        // passive requests do not contribute to the provider request, and passive requests
        // must handle the batching parameters of non-passive requests
        if (request.getIntervalMillis() == LocationRequest.PASSIVE_INTERVAL) {
            continue;
        }

        intervalMs = min(request.getIntervalMillis(), intervalMs);
        quality = min(request.getQuality(), quality);
        maxUpdateDelayMs = min(request.getMaxUpdateDelayMillis(), maxUpdateDelayMs);
        adasGnssBypass |= request.isAdasGnssBypass();
        locationSettingsIgnored |= request.isLocationSettingsIgnored();
        lowPower &= request.isLowPower();
    }

    if (intervalMs == ProviderRequest.INTERVAL_DISABLED) {
        return ProviderRequest.EMPTY_REQUEST;
    }

    if (maxUpdateDelayMs / 2 < intervalMs) {
        // reduces churn if only the batching parameter has changed
        maxUpdateDelayMs = 0;
    }

    // calculate who to blame for power in a somewhat arbitrary fashion. we pick a threshold
    // interval slightly higher that the minimum interval, and spread the blame across all
    // contributing registrations under that threshold (since worksource does not allow us to
    // represent differing power blame ratios).
    long thresholdIntervalMs;
    try {
        thresholdIntervalMs = Math.multiplyExact(Math.addExact(intervalMs, 1000) / 2, 3);
    } catch (ArithmeticException e) {
        // check for and handle overflow by setting to one below the passive interval so passive
        // requests are automatically skipped
        thresholdIntervalMs = LocationRequest.PASSIVE_INTERVAL - 1;
    }

    WorkSource workSource = new WorkSource();
    for (Registration registration : registrations) {
        if (registration.getRequest().getIntervalMillis() <= thresholdIntervalMs) {
            workSource.add(registration.getRequest().getWorkSource());
        }
    }

    return new ProviderRequest.Builder()
            .setIntervalMillis(intervalMs)
            .setQuality(quality)
            .setMaxUpdateDelayMillis(maxUpdateDelayMs)
            .setAdasGnssBypass(adasGnssBypass)
            .setLocationSettingsIgnored(locationSettingsIgnored)
            .setLowPower(lowPower)
            .setWorkSource(workSource)
            .build();
}

// registerWithService(merged, actives) [参数: TMergedRegistration merged 和 ArrayList<TRegistration> actives]
protected boolean registerWithService(ProviderRequest request, Collection<Registration> registrations) {
    return reregisterWithService(ProviderRequest.EMPTY_REQUEST, request, registrations);
}

@GuardedBy("mLock")
@Override
protected boolean reregisterWithService(ProviderRequest oldRequest,
        ProviderRequest newRequest, Collection<Registration> registrations) {
    if (Build.IS_DEBUGGABLE) {
        Preconditions.checkState(Thread.holdsLock(mLock));
    }

    // calculate how long the new request should be delayed before sending it off to the
    // provider, under the assumption that once we send the request off, the provider will
    // immediately attempt to deliver a new location satisfying that request.
    long delayMs;
    if (!oldRequest.isBypass() && newRequest.isBypass()) {
        delayMs = 0;
    } else if (newRequest.getIntervalMillis() > oldRequest.getIntervalMillis()) {
        // if the interval has increased, tell the provider immediately, so it can save power
        // (even though technically this could burn extra power in the short term by producing
        // an extra location - the provider itself is free to detect an increasing interval and
        // delay its own location)
        delayMs = 0;
    } else {
        delayMs = calculateRequestDelayMillis(newRequest.getIntervalMillis(), registrations);
    }

    // the delay should never exceed the new interval
    Preconditions.checkState(delayMs >= 0 && delayMs <= newRequest.getIntervalMillis());

    if (delayMs < MIN_REQUEST_DELAY_MS) {
        setProviderRequest(newRequest);   ---> 到了这里是不是就是我们比较熟悉的流程了
    } else {
        if (D) {
            Log.d(TAG, mName + " provider delaying request update " + newRequest + " by "
                    + TimeUtils.formatDuration(delayMs));
        }

        if (mDelayedRegister != null) {
            mAlarmHelper.cancel(mDelayedRegister);
            mDelayedRegister = null;
        }

        mDelayedRegister = new OnAlarmListener() {
            @Override
            public void onAlarm() {
                synchronized (mLock) {
                    if (mDelayedRegister == this) {
                        mDelayedRegister = null;
                        setProviderRequest(newRequest);
                    }
                }
            }
        };
        // Set WorkSource to null in order to ensure the alarm wakes up the device even when it
        // is idle. Do this when the cost of waking up the device is less than the power cost of
        // not performing the actions set off by the alarm, such as unregistering a location
        // request.
        mAlarmHelper.setDelayedAlarm(delayMs, mDelayedRegister, null);
    }

    return true;
}

setProviderRequest(newRequest) 继续看这个,比较熟悉的流程看下

void setProviderRequest(ProviderRequest request) {
    if (mDelayedRegister != null) {
        mAlarmHelper.cancel(mDelayedRegister);
        mDelayedRegister = null;
    }

    EVENT_LOG.logProviderUpdateRequest(mName, request);
    mProvider.getController().setRequest(request);    ---> 这个就是各个调用到 Provide

    FgThread.getHandler().post(() -> {
        for (IProviderRequestListener listener : mProviderRequestListeners) {
            try {
                listener.onProviderRequestChanged(mName, request);
            } catch (RemoteException e) {
                mProviderRequestListeners.remove(listener);
            }
        }
    });
}

至此,Android 13 的GPS定位发起大致梳理完毕,下一篇有时间继续。只想吐槽一句,搞得真繁琐,调用流程……

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值