浅谈framework之ActivityManagerService

1. 前言

OS世界的三大天尊之一,ActivityManagerService,下文将称其AMS,他的作用包括进程管理,内存管理,组件管理等,作用毋庸置疑,学习AMS,跟踪过程,弄懂原理,对系统开发定制有极大的帮助,对应用开发也可以借鉴他的架构设计自己的独有模式,并且可以全局分析上层可能出现的问题。有时间就填坑吧,哈哈哈。

2. UI相关

作为Android系统核心应用,SystemUI负责反馈系统及应用状态并与用户保持大量的交互。耳熟能详的三栏:StatusBar(状态栏)、NavigationBar(导航栏)与Notification Panel(通知栏),以及Recents(近期任务界面),使用起来方便又快捷。另外Keyguard(锁屏界面)也是属于SystemUI的一部分。并且在Android8.0代码中,Keyguard模块已经从外部被合并到SystemUI源码目录下。

SystemUI 启动

Launcher 启动

3. 任务栈相关

任务栈

4. 组件相关

AMS与四大组件的注册,启动,注销相关,这里只说一下Activity组件的注册,启动,注销过程,此过程大体如下:

在这里插入图片描述

中间细节图如下:
在这里插入图片描述
上图是根据android4.4.2所绘,中间还有一个细节需要提一下,如下:
framworks/base/services/java/com/android/server/am/ActivityStackSupervisor.java


    void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // Is this activity's application already running?
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        r.task.stack.setLaunchTime(r);
         //1
        if (app != null && app.thread != null) {
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    // Don't add this if it is a platform component that is marked
                    // to run in multiple processes, because this is actually
                    // part of the framework so doesn't make sense to track as a
                    // separate apk in the process.
                    app.addPackage(r.info.packageName, mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }
         //2
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

从注释1的判断来看,说明当前的Activity所在的进程存在的话,则执行realStartActivityLocked,也就是上图所绘流程。当前Activity所在的进程不存在的情况了则走注释2处的startProcessLocked的函数。

这里与app的冷启动与热启动相关。这部分之前有写过相关的内容,下面我则挪过来用好了,懒~

4.1 客户端请求

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

private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
    try {
       ......
      // Start the process.  It will either succeed and return a result containing
      // the PID of the new process, or else throw a RuntimeException.
     Process.ProcessStartResult startResult= Process.start("android.app.ActivityThread",
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, null);
      .......
    }
}

===========/frameworks/base/core/java/android/os/Process.java =========

public static final ProcessStartResult start(final String processClass,
                                  final String niceName,
                                  int uid, int gid, int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String[] zygoteArgs) {
try {
   return startViaZygote(processClass, niceName, uid, gid, gids,
          debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
 } catch (ZygoteStartFailedEx ex) {
            Log.e(LOG_TAG,
                    "Starting VM process through Zygote failed");
            throw new RuntimeException(
                    "Starting VM process through Zygote failed", ex);
   }
}

===========/frameworks/base/core/java/android/os/Process.java =========

private static ProcessStartResult startViaZygote(final String processClass,
                                  final String niceName,
                                  final int uid, final int gid,
                                  final int[] gids,
                                  int debugFlags, int mountExternal,
                                  int targetSdkVersion,
                                  String seInfo,
                                  String[] extraArgs)
                                  throws ZygoteStartFailedEx {
        synchronized(Process.class) {
            ……
            return zygoteSendArgsAndGetResult(argsForZygote);
        }
}

startViaZygote的绝大部分代码都在处理传递到Zygote中的参数,与Zygote通信通过zygoteSendArgsAndGetResult()方法完成:
===========/frameworks/base/core/java/android/os/Process.java =========

private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
        openZygoteSocketIfNeeded();//确保和Zygote通信的socket已被打开
        try {
            sZygoteWriter.write(Integer.toString(args.size()));
            sZygoteWriter.newLine();
            int sz = args.size();
            for (int i = 0; i < sz; i++) {//发送请求参数到Zygote
                String arg = args.get(i);
                if (arg.indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx(
                            "embedded newlines not allowed");
                }
                sZygoteWriter.write(arg);
                sZygoteWriter.newLine();
            }
            sZygoteWriter.flush();
            ProcessStartResult result = new ProcessStartResult();
            result.pid = sZygoteInputStream.readInt();  
          if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            result.usingWrapper = sZygoteInputStream.readBoolean();
            return result;
        } catch (IOException ex) {
            try {
                if (sZygoteSocket != null) {
                    sZygoteSocket.close();
                }
            } catch (IOException ex2) {
                // we're going to fail anyway
                Log.e(LOG_TAG,"I/O exception on routine close", ex2);
            }
            sZygoteSocket = null;
            throw new ZygoteStartFailedEx(ex);
        }
    }


4.2 处理客户端请求

首先是到ZygoteInit.java main函数这里开始观察
===/frameworks/base/core/java/com/android/internal/os/ZygoyeInit.java ====

public static void main(String argv[]) {
	……
	runSelectLoop();
	……
}

核心代码在runSelectLoop函数的实现中,继续往下看

===/frameworks/base/core/java/com/android/internal/os/ZygoyeInit.java ====

private static void runSelectLoop() throws MethodAndArgsCaller {
	……
	white(true){
			……
		    if (index < 0) {
                throw new RuntimeException("Error in select()");
            } else if (index == 0) {
                ZygoteConnection newPeer = acceptCommandPeer();
                peers.add(newPeer);
                fds.add(newPeer.getFileDesciptor());
            } else {
                boolean done;
                done = peers.get(index).runOnce();
                if (done) {
                    peers.remove(index);
                    fds.remove(index);
                }
            }
	}
}

上面函数实现中,最终会调用到runOnce函数

===frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java ===

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
        String args[];
        Arguments parsedArgs = null;
        FileDescriptor[] descriptors;
        try {
            args = readArgumentList();//读取客户端发送过来的参数
            descriptors = mSocket.getAncillaryFileDescriptors();
        } catch (IOException ex) {
            Log.w(TAG, "IOException on command socket " + ex.getMessage());
            closeSocket();
            return true;
        }
        if (args == null) {
            // EOF reached.
            closeSocket();
            return true;
        }
        /** the stderr of the most recent request, if avail */
        PrintStream newStderr = null;
        if (descriptors != null && descriptors.length >= 3) {
            newStderr = new PrintStream(
                    new FileOutputStream(descriptors[2]));
        }
        int pid = -1;
        FileDescriptor childPipeFd = null;
        FileDescriptor serverPipeFd = null;
        try {
            parsedArgs = new Arguments(args);
            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            applyDebuggerSystemProperty(parsedArgs);
            applyInvokeWithSystemProperty(parsedArgs);
            int[][] rlimits = null;
            if (parsedArgs.rlimits != null) {
                rlimits = parsedArgs.rlimits.toArray(intArray2d);
            }
            if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
                FileDescriptor[] pipeFds = Libcore.os.pipe();
                childPipeFd = pipeFds[1];
                serverPipeFd = pipeFds[0];
                ZygoteInit.setCloseOnExec(serverPipeFd, true);
            }
            //fork一个新进程
pid=Zygote.forkAndSpecialize(parsedArgs.uid,  parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits,parsedArgs.mountExternal, parsedArgs.seInfo,      parsedArgs.niceName);
        } catch (IOException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (ErrnoException ex) {
            logAndPrintError(newStderr, "Exception creating pipe", ex);
        } catch (IllegalArgumentException ex) {
            logAndPrintError(newStderr, "Invalid zygote arguments", ex);
        } catch (ZygoteSecurityException ex) {
            logAndPrintError(newStderr,
                    "Zygote security policy prevents request: ", ex);
        }
        try {
            if (pid == 0) {//子进程
                // in child
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                // should never get here, the child is expected to either
                // throw ZygoteInit.MethodAndArgsCaller or exec().
                return true;
            } else {//父进程
                // in parent...pid of < 0 means failure
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
}

===frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java ===

private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {
        closeSocket();//关闭子进程中,从Zygote fork过来的服务端socket
        ZygoteInit.closeServerSocket();
        .....
        if (parsedArgs.niceName != null) {
            Process.setArgV0(parsedArgs.niceName);
        }
        if (parsedArgs.runtimeInit) {
            if(parsedArgs.invokeWith!=null) {WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        pipeFd, parsedArgs.remainingArgs);
            } else {
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs);
            }
        } else {
        	......
        }
    }

===frameworks/base/core/java/com/android/internal/os/RuntimeInit.java ===

    public static final void zygoteInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

        redirectLogStreams();

        commonInit();
        nativeZygoteInit();

        applicationInit(targetSdkVersion, argv);
    }

===frameworks/base/core/java/com/android/internal/os/RuntimeInit.java ==

private static void applicationInit(int targetSdkVersion, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        final Arguments args;
        try {
            args = new Arguments(argv);
        } catch (IllegalArgumentException ex) {
            Slog.e(TAG, ex.getMessage());
            // let the process exit
            return;
        }

        // Remaining arguments are passed to the start class's static main
        invokeStaticMain(args.startClass, args.startArgs);
}

===frameworks/base/core/java/com/android/internal/os/RuntimeInit.java ===

 private static void invokeStaticMain(String className, String[] argv)
            throws ZygoteInit.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className);
        } catch (ClassNotFoundException ex) {
            throw new RuntimeException(
                    "Missing class when invoking static main " + className,
                    ex);
        }
        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            throw new RuntimeException(
                    "Missing static main on " + className, ex);
        } catch (SecurityException ex) {
            throw new RuntimeException(
                    "Problem getting static main on " + className, ex);
        }

        int modifiers = m.getModifiers();
          if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
            throw new RuntimeException(
                    "Main method is not public and static on " + className);
          }
        /*
         * This throw gets caught in ZygoteInit.main(), which responds
         * by invoking the exception's run() method. This arrangement
         * clears up all the stack frames that were required in setting
         * up the process.
         */
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

最终是通过反射调用到ActivityThread.java的main函数中。

5. 进程相关

5.1 进程分类

1、foreground process
杀死foreground需要用户响应,因为这个安全优先级是最高的
是用户操作所必须的,任一时间下,仅有少数进程会处于前台,仅当内存实在无法供给它们维持同时运行时才会被杀死。
2、visible process
activity不在前端显示,但也没有完全隐藏,能够看得见,比如弹出一个对话框
可视进程依然被视为是很重要的,非到不杀死它们便无法维持前台进程运行时,才会被杀死。
3、Service process
正在运行的,不在上述两种状态的service
是由 startService() 方法启动的服务,它不会变成上述两类。尽管服务进程不会直接为用户所见,但它们一般都在做着用户所关心的事情(比如在后台播放mp3或者从网上下载东 西)。所以系统会尽量维持它们的运行,除非系统内存不足以维持前台进程和可视进程的运行需要。
4、background process
不可见状态的activity进程,onstop被调用
包含目前不为用户所见的activity(Activity对象的 onStop() 方法已被调用)。这些进程与用户体验没有直接的联系,可以在任意时间被杀死以回收内存供前台进程、可视进程以及服务进程使用。一般来说,会有很多背景进程 运行,所以它们一般存放于一个LRU(最后使用)列表中以确保最后被用户使用的activity最后被杀死。
5、empty process
没有运行任何component的进程,保留这个进程主要是为了缓存的需要

5.2 进程管理

关于Android系统的内存回收机制,相信大家都不陌生,Android基于各个应用进程承载四大组件的状态对应用进程进行重要性评估,并在系统内存紧张时根据重要性由低到高来选择杀死应用进程,以达到释放内存的目的。重要性评估由AMS执行,具体来说就是由updateOomAdjLocked函数决定,这个函数作用就是更新应用进程的重要性。

应用进程(ProcessRecord)的重要性由三个状态值表示:

adj:LMK杀进程的评分依据
procState:指示进程状态
schedGroup:指示进程调度策略

framworks/base/services/java/com/android/server/am/ActivityManagerService.java

    final void updateOomAdjLocked() {
		//此处省略部分代码
        for (int i=N-1; i>=0; i--) {
            ProcessRecord app = mLruProcesses.get(i);
            if (!app.killedByAm && app.thread != null) {
                app.procStateChanged = false;
                final boolean wasKeeping = app.keeping;
                //关注点1
                computeOomAdjLocked(app, ProcessList.UNKNOWN_ADJ, TOP_APP, true, now); 
                //此处省略部分代码
				//关注点2
                applyOomAdjLocked(app, wasKeeping, TOP_APP, true, false, now); 

                // Count the number of process types.
                switch (app.curProcState) {
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
                    case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
                        mNumCachedHiddenProcs++;
                        numCached++;
                        if (numCached > cachedProcessLimit) {
                        	//关注点3
                            killUnneededProcessLocked(app, "cached #" + numCached);
                        }
                        break;
                    case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
                        if (numEmpty > ProcessList.TRIM_EMPTY_APPS
                                && app.lastActivityTime < oldTime) {
                            killUnneededProcessLocked(app, "empty for "
                                    + ((oldTime + ProcessList.MAX_EMPTY_TIME - app.lastActivityTime)
                                    / 1000) + "s");
                        } else {
                            numEmpty++;
                            if (numEmpty > emptyProcessLimit) {
                                killUnneededProcessLocked(app, "empty #" + numEmpty);
                            }
                        }
                        break;
                    default:
                        mNumNonCachedProcs++;
                        break;
                }
			//此处省略部分代码
    }

1、调用computeOomAdjLocked来计算进程的oom_adj的值;

2、调用applyOomAdjLocked来更新进程的oom_adj的值;

3、调用killUnneededProcessLocked来kill掉不适用的进程。

updateOomAdjLocked在后面还做了一些对内存的处理优化操作,这里就不介绍了;这里有一个疑问,底层和上层都有kill进程的过程,其中有什么区别呢,我的想法是这样的,底层的kill主要发生在进程出现Low Memory的时候才去做,而上层在AMS中是系统在检测到内存不足时清理缓存的一个重要过程。

下面再看上面关注点2调用的函数:

private final boolean applyOomAdjLocked(ProcessRecord app, boolean wasKeeping,
            ProcessRecord TOP_APP, boolean doingAll, boolean reportingProcessState, long now) {
       //省略
        if (app.curAdj != app.setAdj) {
            if (Process.setOomAdj(app.pid, app.curAdj)) {
                if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(
                    TAG, "Set " + app.pid + " " + app.processName +
                    " adj " + app.curAdj + ": " + app.adjType);
                app.setAdj = app.curAdj;
            } else {
                success = false;
                Slog.w(TAG, "Failed setting oom adj of " + app + " to " + app.curAdj);
            }
        }
       //省略
        return success;
    }

curAdj是computeOomAdjLocked计算出的adj值,通过调用Process.setOomAdj(int pid, int amt)往下进行设置。
updateOomAdjLocked在后面还做了一些对内存的处理优化操作,这里就不介绍了;这里有一个疑问,底层和上层都有kill进程的过程,其中有什么区别呢,我的想法是这样的,底层的kill主要发生在进程出现Low Memory的时候才去做,而上层在AMS中是系统在检测到内存不足时清理缓存的一个重要过程。

public static final native boolean setOomAdj(int pid, int amt);

5.3 底层实现

framworks/base/core/jni/android_util_Process.cpp

jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
                                      jint pid, jint adj)
{
#ifdef HAVE_OOM_ADJ
    char text[64];
    sprintf(text, "/proc/%d/oom_adj", pid);
    int fd = open(text, O_WRONLY);
    if (fd >= 0) {
        sprintf(text, "%d", adj);
        write(fd, text, strlen(text));
        close(fd);
    }
    return true;
#endif
    return false;
}

可以看到这段函数打开了对应的位置的oom_adj文件,并将adj的值写到这个文件中,也即是达到了更新对应进程oom_adj值的效果。

5.4 LMK原理

内核LMK的原理很简单:首先注册了shrinker,在内存紧张的时候会触发lowmem_shrink(linux 高版本是lowmem_scan)方法,这个方法要做的就是找到一个进程,然后杀掉他,释放一些内存。

获取剩余内存的大小,和Minfree内存阀值做比较,找到对应的内存阀值,找到对应的adj值。
遍历所有的进程,大于该adj的值的进程是要杀掉的目标进程, 但是并不是全部杀掉,而是找到adj最大的进程杀掉,如果最大adj有多个相同adj进程,则杀掉占用内存最大的一个。

5.5 后记

andorid 5.0及其后面版本跟上面会有一定差异,最大的区别是与驱动通信的方式的改变。
整个流程图如下(网图,自己懒得画了):
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
@org.springframework.stereotype.Service 是Spring框架中的一个注解,用于标注业务层组件(service)。它的作用是将一个类标识为Spring的服务层组件,让Spring能够自动扫描并将其实例化为Bean,以供其他组件使用。 在Spring框架中,使用@Service注解来标注业务层的实现类,它与其他注解(如@Controller、@Repository等)一样,都是通过@Component注解来实现的。@Service注解的作用是告诉Spring框架,被标注的类是业务层组件,需要被Spring进行管理。 使用@Service注解标注的类,可以通过依赖注入的方式使用,即其他组件可以直接使用@Autowired注解来注入@Service标注的业务层组件。而@Autowired注解则是Spring框架提供的一种自动装配的方式,它可以自动将标注了@Autowired注解的属性或构造函数参数与相应的Bean进行关联。在注入时,Spring会根据类型进行匹配,找到对应的Bean进行注入。 需要注意的是,如果一个类既需要被Spring注入,又需要被当做提供者(provider),那么不能同时使用@Service和@Component注解来标注该类。因为同名的注解不能重复导入。如果确实需要同时使用这两个注解,可以将@Spring注解替换成@Component注解。 总结起来,@org.springframework.stereotype.Service注解是Spring框架中用于标识业务层组件(service)的注解,它能够让Spring自动扫描并实例化标注了该注解的类,并且可以通过@Autowired注解进行依赖注入。同时,需要注意如果一个类既需要被Spring注入,又需要被当做提供者,不能同时使用@Service和@Component注解,需要将@Service替换成@Component注解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值