jQuery鼠标指针特效

Android 11 -- app 服务保活

app服务保活 (android 11 源码)

frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

stop后台service的逻辑:

AMS的doStopUidLocked方法会先stop 后台service,再去更新uid并分发uid的change
stopInBackgroundLocked回调后,service不一定会真被stop

void stopInBackgroundLocked(int uid) {
        // Stop all services associated with this uid due to it going to the background
        // stopped state.
        // 获取该uid下的所有service
        ServiceMap services = mServiceMap.get(UserHandle.getUserId(uid));
        ArrayList<ServiceRecord> stopping = null;
        if (services != null) {
            for (int i = services.mServicesByInstanceName.size() - 1; i >= 0; i--) {
                ServiceRecord service = services.mServicesByInstanceName.valueAt(i);
                 // start方式启动的service
                if (service.appInfo.uid == uid && service.startRequested) {
                    if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
                            service.appInfo.targetSdkVersion, -1, false, false, false)
                            != ActivityManager.APP_START_MODE_NORMAL) {
                        if (stopping == null) {
                            stopping = new ArrayList<>();
                        }
                        String compName = service.shortInstanceName;

                        //add  包名过滤防止它被杀
                        if(compName.contains("com.google.wangyiyun"))
                            continue;
                        //end
                        ......
                        
                        // 將当前service添加进stoppping列表
                        stopping.add(service);

                        // If the app is under bg restrictions, also make sure that
                        // any notification is dismissed
                        if (appRestrictedAnyInBackground(
                                service.appInfo.uid, service.packageName)) {
                            cancelForegroundNotificationLocked(service);
                        }
                    }
                }
            }
            if (stopping != null) {
                for (int i=stopping.size()-1; i>=0; i--) {
                    ServiceRecord service = stopping.get(i);
                    service.delayed = false;
                    services.ensureNotStartingBackgroundLocked(service);
                    // stop service
                    stopServiceLocked(service);
                }
            }
        }
    }
    

//这个函数用停止app的服务
private void stopServiceLocked(ServiceRecord service) {
        if (service.delayed) {
            // If service isn't actually running, but is being held in the
            // delayed list, then we need to keep it started but note that it
            // should be stopped once no longer delayed.
            if (DEBUG_DELAYED_STARTS) Slog.v(TAG_SERVICE, "Delaying stop of pending: " + service);
            service.delayedStop = true;
            return;
        }
        StatsLog.write(StatsLog.SERVICE_STATE_CHANGED, service.appInfo.uid,
                service.name.getPackageName(), service.name.getClassName(),
                StatsLog.SERVICE_STATE_CHANGED__STATE__STOP);
        synchronized (service.stats.getBatteryStats()) {
            service.stats.stopRunningLocked();
        }
        service.startRequested = false;
        if (service.tracker != null) {
            service.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(),
                    SystemClock.uptimeMillis());
        }
        service.callStart = false;

        bringDownServiceIfNeededLocked(service, false, false);
    }
    

bringDownServiceIfNeededLocked(...)
private final void bringDownServiceIfNeededLocked(ServiceRecord r, boolean knowConn,
            boolean hasConn) {

        if (isServiceNeededLocked(r, knowConn, hasConn)) {
            return;
        }
        // 如果有新拉起service的需求,本次不会stop该service
        if (mPendingServices.contains(r)) {
            return;
        }
        bringDownServiceLocked(r);
    }

    

(android-12)app进入后台,关掉杀死serivce
参考一

实际案例:Android 11 startService启动服务,应用置于后台超过1min,服务被销毁过程分析

Logcat打印:

W ActivityManager: Stopping service due to app idle: u0a137 -1m19s820ms com.xxx.factorysettings/.services.xxxService

app被切到后台,经过一分钟后,ActiveServices::stopInBackgroundLocked(...)

void stopInBackgroundLocked(int uid) {
        //因为app将进入到后台,停止与此uid关联的所有服务 uid为app的uid
        ServiceMap services = mServiceMap.get(UserHandle.getUserId(uid));
        ArrayList<ServiceRecord> stopping = null;
        if (services != null) {
            for (int i = services.mServicesByInstanceName.size() - 1; i >= 0; i--) {
                ServiceRecord service = services.mServicesByInstanceName.valueAt(i);
                if (service.appInfo.uid == uid && service.startRequested) {
                //判断条件:如果app的getAppStartModeLocked(...)不等于ActivityManager.APP_START_MODE_NORMAL,就要被stop
                    if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
                            service.appInfo.targetSdkVersion, -1, false, false, false)
                            != ActivityManager.APP_START_MODE_NORMAL) {
                        if (stopping == null) {
                            stopping = new ArrayList<>();
                        }
                        String compName = service.shortInstanceName;
                        EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
                        StringBuilder sb = new StringBuilder(64);
                        sb.append("Stopping service due to app idle: ");
                        UserHandle.formatUid(sb, service.appInfo.uid);
                        sb.append(" ");
                        TimeUtils.formatDuration(service.createRealTime
                                - SystemClock.elapsedRealtime(), sb);
                        sb.append(" ");
                        sb.append(compName);
                        Slog.w(TAG, sb.toString());//打印日志标记点
                        //符合停止条件,就让他进入stop集合
                        stopping.add(service);

                        // If the app is under bg restrictions, also make sure that
                        // any notification is dismissed
                        if (appRestrictedAnyInBackground(
                                service.appInfo.uid, service.packageName)) {
                            cancelForegroundNotificationLocked(service);
                        }
                    }
                }
            }
            if (stopping != null) {
                //进入stop集合的service,开始逐个stopping(killer)
                for (int i=stopping.size()-1; i>=0; i--) {
                    ServiceRecord service = stopping.get(i);
                    service.delayed = false;
                    services.ensureNotStartingBackgroundLocked(service);
                    stopServiceLocked(service);
                }
            }
        }
    }

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
            int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
        if (mInternal.isPendingTopUid(uid)) {
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        //add text
        if(packageName != null && packageName.equals("com.xx.xxxx")){
            return ActivityManager.APP_START_MODE_NORMAL;
        }
        //add text
        UidRecord uidRec = mProcessList.getUidRecordLocked(uid);
        if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
                + packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
                + (uidRec != null ? uidRec.idle : false));
....

实际案例:Android 11 后台启动服务 报错

Logcat:

W ActivityManager: Background start not allowed: service Intent 
{ cmp=com.android.deskclock/.addition.resource.ResourceLoadService (has extras) } to ...

/frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, boolean fgRequired, String callingPackage,
            @Nullable String callingFeatureId, final int userId,
            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
            ...
            if (forcedStandby || (!r.startRequested && !fgRequired)) {
            //检查是否允许app后台启动service
            final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
                    r.appInfo.targetSdkVersion, callingPid, false, false, forcedStandby);
            //sign 1.0 如果 allowed != ActivityManager.APP_START_MODE_NORMAL == false 不允许
            if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
                Slog.w(TAG, "Background start not allowed: service "
                        + service + " to " + r.shortInstanceName
                        + " from pid=" + callingPid + " uid=" + callingUid
                        + " pkg=" + callingPackage + " startFg?=" + fgRequired);
                if (allowed == ActivityManager.APP_START_MODE_DELAYED || forceSilentAbort) {
                    // In this case we are silently disabling the app, to disrupt as
                    // little as possible existing apps.
                    return null;
                }
                if (forcedStandby) {
                    // This is an O+ app, but we might be here because the user has placed
                    // it under strict background restrictions.  Don't punish the app if it's
                    // trying to do the right thing but we're denying it for that reason.
                    if (fgRequired) {
                        if (DEBUG_BACKGROUND_CHECK) {
                            Slog.v(TAG, "Silently dropping foreground service launch due to FAS");
                        }
                        return null;
                    }
                }
                // This app knows it is in the new model where this operation is not
                // allowed, so tell it what has happened.
                UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(r.appInfo.uid);
                return new ComponentName("?", "app is in background uid " + uidRec);
            }
        }
        ...     
}

frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
            int callingPid, boolean alwaysRestrict, boolean disabledOnly, boolean forcedStandby) {
        if (mInternal.isPendingTopUid(uid)) {
        ...
        final int startMode = (alwaysRestrict)
                        ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
                        : appServicesRestrictedInBackgroundLocked(uid, packageName,
                                packageTargetSdk);
                if (DEBUG_BACKGROUND_CHECK) {
                    Slog.d(TAG, "checkAllowBackground: uid=" + uid
                            + " pkg=" + packageName + " startMode=" + startMode
                            + " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid, false)
                            + " onwhitelist(ei)=" + isOnDeviceIdleWhitelistLocked(uid, true));
                }
                //对低版本的兼容
                if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
                    if (callingPid >= 0) {
                        ProcessRecord proc;
                        synchronized (mPidsSelfLocked) {
                            proc = mPidsSelfLocked.get(callingPid);
                        }
                        if (proc != null &&
                                !ActivityManager.isProcStateBackground(proc.getCurProcState())) {
                            // Whoever is instigating this is in the foreground, so we will allow it
                            // to go through.
                            return ActivityManager.APP_START_MODE_NORMAL;
                        }
                    }
                }
                return startMode;
        ...
}

//1.Persistent app 允许  2.background白名单允许 3.battery白名单允许
int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
        // Persistent app?
        if (mPackageManagerInt.isPackagePersistent(packageName)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " is persistent; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }

        // Non-persistent but background whitelisted?
        if (uidOnBackgroundWhitelist(uid)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on background whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }

        // Is this app on the battery whitelist?
        if (isOnDeviceIdleWhitelistLocked(uid, /*allowExceptIdleToo=*/ false)) {
            if (DEBUG_BACKGROUND_CHECK) {
                Slog.i(TAG, "App " + uid + "/" + packageName
                        + " on idle whitelist; not restricted in background");
            }
            return ActivityManager.APP_START_MODE_NORMAL;
        }

        // None of the service-policy criteria apply, so we apply the common criteria
        return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
    }

//如果获取app的uid -->activityManagerService中提供的api
public String[] getPackagesForUid(int uid) {
      return mActivityManagerService.mContext.getPackageManager().getPackagesForUid(uid);
}

ps -A | grep systemui
u0_a127(uid)         709    265 14421016 241628 0                  0 S com.android.systemui
u0_a127(uid)        3333    265 14038800 180276 0                  0 S com.android.systemui:screenshot

后台执行限制总结_background start not allowed: service intent

posted @ 2024-03-24 17:32  僵小七  阅读(84)  评论(0编辑  收藏  举报