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

查询APP里是否有服务

Intent serviceIntent = new Intent();
String[] packageNames = {"com.tencent.qqmusic", "com.spotify.music","com.android.systemui"};
for (String pkgName : packageNames) {
    serviceIntent.setPackage(pkgName);
    List<ResolveInfo> resolveInfos = yourContext.getPackageManager().queryIntentServices(serviceIntent, 0);
    Log.d(TAG, "Package: " + pkgName);
    for (ResolveInfo resolveInfo : resolveInfos) {
        Log.d(TAG, "Intent service name: " + resolveInfo.serviceInfo);
    }
}

查询服务是否work

//从Android O开始,此方法不再可用于第三方应用程序。为了向后兼容,它仍然会返回调用者自己的服务

public static boolean isSeviceWorked(Context context, String serviceName) {
        ActivityManager myManager = (ActivityManager) context
                .getSystemService(Context.ACTIVITY_SERVICE);
        ArrayList<RunningServiceInfo> runningService = (ArrayList<RunningServiceInfo>) myManager
                .getRunningServices(30);
        for (int i = 0; i < runningService.size(); i++) {
            if (runningService.get(i).service.getClassName().toString().equals(
                    serviceName)) {
                return true;
            }
        }
        return false;
    }

Android T 关于系统应用内服务自启问题

Scheduling restart of crashed service解决方案与源码分析-CSDN博客

问题描述:

业务要求,在系统内开发一个app,因为要读写settings 属性的参数,所以给了android:sharedUserId="android.uid.system"和系统签名。

在最近任务界面,移除它的后台,发现它内部的一个服务会重启。但是服务onStartCommand的返回值用的是默认的return super.onStartCommand(intent, flags, startId);,奇怪?

//内置源码编译
android_app {
    name: "xxApp",
    resource_dirs: ["res"],
    sdk_version: "current",
    srcs: [
        "src/**/*.java",
    ],
    certificate: "platform",
    product_specific: true,
    static_libs: [
        "androidx.annotation_annotation",
        "androidx.lifecycle_lifecycle-common",
    ],
}

日志:

system_server W  Scheduling restart of crashed service com.xx.xx/.service_broadcast.xx in 1000ms for start-requested
system_server I  Start proc 3029:com.xx.xx/1000 for service {com.xx.xx/com.portworld.xx.service_broadcast.xx}

ps -A | grep xxx 查进程 ,发现它是system级别进程.

system         564   280 19034136 338168 do_epoll_wait      0 S system_server
u0_a73         752   280 16304600 219428 do_epoll_wait      0 S com.android.systemui
system        4248   280 14745008 137992 do_epoll_wait      0 S com.xxx.xxtapp
服务返回参数

一共四种模式,
START_STICKY (1)模式在服务死掉后被系统自动重启拉活,但是不会保留之前的intent参数;

START_STICKY_COMPATIBILITY (0)是START_STICKY 的兼容模式,不保证服务死掉后被系统自动拉活;

START_NOT_STICKY(2)服务死掉系统不会自动去拉活;

START_REDELIVER_INTENT(3)模式在服务死掉后被系统自动重启拉活,并且保留之前的intent参数。

源码跟踪
/** @return {@code true} if the restart is scheduled. */
    private final boolean scheduleServiceRestartLocked(ServiceRecord r, boolean allowCancel) {
        android.util.Log.d("txx", Log.getStackTraceString(new Throwable()));
        if (mAm.mAtmInternal.isShuttingDown()) {
            Slog.w(TAG, "Not scheduling restart of crashed service " + r.shortInstanceName
                    + " - system is shutting down");
            return false;
        }

       ...
            android.util.Log.d("txx","allowCancel: "+allowCancel);
            if (allowCancel) {
                final boolean shouldStop = r.canStopIfKilled(canceled);
                //START_STICKY类型canStopIfKilled方法为false,START_NOT_STICKY则为true
                android.util.Log.d("txx","shouldStop: "+shouldStop);
                if (shouldStop && !r.hasAutoCreateConnections()) {
                    // Nothing to restart.
                    return false;
                }
                reason = (r.startRequested && !shouldStop) ? "start-requested" : "connection";
            } else {
                reason = "always";
            }
			//下面就是服务重启逻辑
            r.totalRestartCount++;
            if (r.restartDelay == 0) {
                r.restartCount++;
                r.restartDelay = minDuration;
            } else if (r.crashCount > 1) {
                r.restartDelay = mAm.mConstants.BOUND_SERVICE_CRASH_RESTART_DURATION
                        * (r.crashCount - 1);
            } else {
            ...

日志打印堆栈:

at com.android.server.am.ActiveServices.scheduleServiceRestartLocked(ActiveServices.java:3701)
at com.android.server.am.ActiveServices.killServicesLocked(ActiveServices.java:5556)
at com.android.server.am.ActivityManagerService.cleanUpApplicationRecordLocked(ActivityManagerService.java:12424)
at com.android.server.am.ActivityManagerService.handleAppDiedLocked(ActivityManagerService.java:3230)
at com.android.server.am.ActivityManagerService.appDiedLocked(ActivityManagerService.java:3337)
at com.android.server.am.ActivityManagerService$AppDeathRecipient.binderDied(ActivityManagerService.java:1478)

txx  D  allowCancel: true
txx  D  shouldStop: false

通过日志发现,shouldStop为false,所以它会进入到重启的逻辑。估计是system级别的Service默认被设定为了START_STICKY。

解决方案:

 	@Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        ...
        //return super.onStartCommand(intent, flags, startId);
        return START_NOT_STICKY;
    }

PS: 自定义服务保活,把它搞成system级别 就行了 有点暴力了。

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