AMS进程管理--LRU篇

AMS是Android操作系统中的一个核心组件,它的全称:Activity Manager Service,但它不仅管理Activity,更是Android应用程序的管理器。负责管理应用的生命周期、任务栈(Android12后委托给ATMS管理)、进程和活动之间的切换等。

由于AMS的代码量十分庞大,需要有针对性的研究才不会陷入源码的海洋无法自拔。本文将结合源码对AMS的进程管理展开分析。本文基于Android12分析,以前的版本的源码略有差异,比如进程管理优先级的代码,12以前是放到AMS中,12之后,主要委托到了ProcessList类中,但核心思想和算法没有改变。

核心思想

对队列中的进程进行调整,根据hasActivity,hasService条件,将整个队列划分为三个区域。最后根据LRU算法,对进程所在的区域中调整位置。

分析过程已经贴在代码注释中。

ps:由于分析是本人的理解,难免有误差,所以会保存源码中的英文注释。

核心代码

final void updateLruProcessLocked(ProcessRecord app, boolean activityChange,
            ProcessRecord client) {
        final boolean hasActivity = app.hasActivitiesOrRecentTasks() || app.hasClientActivities()
                || app.treatLikeActivity;
        final boolean hasService = false; // not impl yet. app.services.size() > 0;
        if (!activityChange && hasActivity) {
            // The process has activities, so we are only allowing activity-based adjustments
            // to move it.  It should be kept in the front of the list with other
            // processes that have activities, and we don't want those to change their
            // order except due to activity operations.
            //进程中的activity没有改变,就不需要调整
            return;
        }

        //id自增,保证唯一性
        mLruSeq++;
        final long now = SystemClock.uptimeMillis();
        //保存更新调整后的时间
        app.lastActivityTime = now;

        // First a quick reject: if the app is already at the position we will
        // put it, then there is nothing to do.
        //快速校验,如果当前有包含activity的进程,并且mLruProcesses的队尾进程已经是当前的,就不需要调整
        if (hasActivity) {
            final int N = mLruProcesses.size();
            if (N > 0 && mLruProcesses.get(N - 1) == app) {
                return;
            }
        } else {//其他类型的进程,包括有service和不含service(other类型)进程
            //mLruProcessServiceStart 是mLruProcesses队列的指针,指向service进程队头的位置
            if (mLruProcessServiceStart > 0
                    && mLruProcesses.get(mLruProcessServiceStart-1) == app) {
                //mLruProcesses的队尾已经是当前的(包含service的进程),不需要调整
                return;
            }
        }
        //获取当前进程的位置,如果没有的,就是-1
        int lrui = mLruProcesses.lastIndexOf(app);
        //如果app是系统进程,有做过system应用的同学知道,可以在application下申明是否是isPersistent属性
        if (app.isPersistent() && lrui >= 0) {
            // We don't care about the position of persistent processes, as long as
            // they are in the list.
           //系统进程不管
            return;
        }
        //如果已经存在
        if (lrui >= 0) {
            //不在下面对应队列中,则需要移除后重新调整位置
            if (lrui < mLruProcessActivityStart) {
                mLruProcessActivityStart--;
            }
            if (lrui < mLruProcessServiceStart) {
                mLruProcessServiceStart--;
            }
            mLruProcesses.remove(lrui);
        }

        int nextIndex;
        int nextActivityIndex = -1;
        if (hasActivity) {
            final int N = mLruProcesses.size();
            //赋值给调整后(前面已经-1)的指针位置,原位置会让给当前进程
            nextIndex = mLruProcessServiceStart;
            //当前进程没有activity
            if (!app.hasActivitiesOrRecentTasks() && !app.treatLikeActivity
                    && mLruProcessActivityStart < (N - 1)) {
                // Process doesn't have activities, but has clients with
                // activities...  move it up, but below the app that is binding to it.
                
                int pos = N - 1;
                //下面的循环目的是将相同进程有很多Client端的进程归并
                while (pos > mLruProcessActivityStart) {
                    final ProcessRecord posproc = mLruProcesses.get(pos);
                    if (posproc.info.uid == app.info.uid) {
                        // Technically this app could have multiple processes with different
                        // activities and so we should be looking for the actual process that
                        // is bound to the target proc...  but I don't really care, do you?
                        break;
                    }
                    pos--;
                }
                //找到对应位置插入
                mLruProcesses.add(pos, app);
                // If this process is part of a group, need to pull up any other processes
                // in that group to be with it.
                int endIndex = pos - 1;
                if (endIndex < mLruProcessActivityStart) {
                    endIndex = mLruProcessActivityStart;
                }
                nextActivityIndex = endIndex;
                updateClientActivitiesOrdering(app, pos, mLruProcessActivityStart, endIndex);
            } else {
                // Process has activities, put it at the very tipsy-top.
                //当前进程有activity直接放到队尾
                mLruProcesses.add(app);
                nextActivityIndex = mLruProcesses.size() - 1;
            }
        } else if (hasService) {
            // Process has services, put it at the top of the service list.
            //有service,把进程放到service的末端,也即是hasActivity段的开头
            mLruProcesses.add(mLruProcessActivityStart, app);
            nextIndex = mLruProcessServiceStart;
            //将mLruProcessActivityStart hasActivity的起始索引+1
            mLruProcessActivityStart++;
        } else  {
            // Process not otherwise of interest, it goes to the top of the non-service area.
            //即没有activity也没有service的进程
            int index = mLruProcessServiceStart;
            if (client != null) {
                // If there is a client, don't allow the process to be moved up higher
                // in the list than that client.
                int clientIndex = mLruProcesses.lastIndexOf(client);
               
                if (clientIndex <= lrui) {
                    // Don't allow the client index restriction to push it down farther in the
                    // list than it already is.
                    clientIndex = lrui;
                }
                if (clientIndex >= 0 && index > clientIndex) {
                    index = clientIndex;
                }
            }
            if (DEBUG_LRU) Slog.d(TAG_LRU, "Adding at " + index + " of LRU list: " + app);
            mLruProcesses.add(index, app);
            nextIndex = index - 1;
            mLruProcessActivityStart++;
            mLruProcessServiceStart++;
            if (index > 1) {
                updateClientActivitiesOrdering(app, mLruProcessServiceStart - 1, 0, index - 1);
            }
        }
        //保存给app自增后的唯一id
        app.lruSeq = mLruSeq;

        // If the app is currently using a content provider or service,
        // bump those processes as well.
        //这里是对进程中有service和contentProvider的情况下,需要将其包含的进程也加入到队列中
        for (int j = app.connections.size() - 1; j >= 0; j--) {
            ConnectionRecord cr = app.connections.valueAt(j);
            if (cr.binding != null && !cr.serviceDead && cr.binding.service != null
                    && cr.binding.service.app != null
                    && cr.binding.service.app.lruSeq != mLruSeq
                    && (cr.flags & Context.BIND_REDUCTION_FLAGS) == 0
                    && !cr.binding.service.app.isPersistent()) {
                if (cr.binding.service.app.hasClientActivities()) {
                    if (nextActivityIndex >= 0) {
                        nextActivityIndex = updateLruProcessInternalLocked(cr.binding.service.app,
                                now,
                                nextActivityIndex, mLruSeq,
                                "service connection", cr, app);
                    }
                } else {
                    nextIndex = updateLruProcessInternalLocked(cr.binding.service.app,
                            now,
                            nextIndex, mLruSeq,
                            "service connection", cr, app);
                }
            }
        }
        for (int j = app.conProviders.size() - 1; j >= 0; j--) {
            ContentProviderRecord cpr = app.conProviders.get(j).provider;
            if (cpr.proc != null && cpr.proc.lruSeq != mLruSeq && !cpr.proc.isPersistent()) {
                nextIndex = updateLruProcessInternalLocked(cpr.proc, now, nextIndex, mLruSeq,
                        "provider reference", cpr, app);
            }
        }
    }

总结

核心在于根据进程状态(是否存在activity和service)去调整mLruProcessServiceStart和mLruProcessActivityStart两个指针的位置,维护活动的列表中3个区域里各自进程优先级。

当内存不足时,Android系统会在根据进程所在区域的优先级去回收进程,当然这里不是简单粗暴的从头还是回收,它会结合进程的重要性做调整,这就是下一篇会讲到的Adj算法。

以下是C语言实现存储管理中的FIFO算法LRU算法的代码示例: FIFO算法: ```c #include <stdio.h> #define MAXSIZE 3 int main() { int pages[MAXSIZE], frames[MAXSIZE], temp[MAXSIZE]; int i, j, k, page_faults = 0, flag = 0, pos = 0; printf("Enter the reference string: "); for(i = 0; i < MAXSIZE; ++i){ scanf("%d", &pages[i]); } for(i = 0; i < MAXSIZE; ++i){ frames[i] = -1; } for(i = 0; i < MAXSIZE; ++i){ flag = 0; for(j = 0; j < MAXSIZE; ++j){ if(frames[j] == pages[i]){ flag = 1; break; } } if(flag == 0){ frames[pos] = pages[i]; pos = (pos + 1) % MAXSIZE; ++page_faults; } printf("\n"); for(j = 0; j < MAXSIZE; ++j){ printf("%d\t", frames[j]); } } printf("\nTotal page faults: %d", page_faults); return 0; } ``` LRU算法: ```c #include <stdio.h> #define MAXSIZE 3 int main() { int pages[MAXSIZE], frames[MAXSIZE], temp[MAXSIZE]; int i, j, k, page_faults = 0, flag = 0, pos = 0, max, min; printf("Enter the reference string: "); for(i = 0; i < MAXSIZE; ++i){ scanf("%d", &pages[i]); } for(i = 0; i < MAXSIZE; ++i){ frames[i] = -1; } for(i = 0; i < MAXSIZE; ++i){ flag = 0; for(j = 0; j < MAXSIZE; ++j){ if(frames[j] == pages[i]){ flag = 1; break; } } if(flag == 0){ for(j = 0; j < MAXSIZE; ++j){ temp[j] = 0; for(k = i - 1; k >= 0; --k){ if(frames[j] == pages[k]){ temp[j] = 1; break; } } } flag = 0; for(j = 0; j < MAXSIZE; ++j){ if(temp[j] == 0){ pos = j; flag = 1; break; } } if(flag == 0){ max = temp[0]; pos = 0; for(j = 1; j < MAXSIZE; ++j){ if(temp[j] > max){ max = temp[j]; pos = j; } } } frames[pos] = pages[i]; ++page_faults; } printf("\n"); for(j = 0; j < MAXSIZE; ++j){ printf("%d\t", frames[j]); } } printf("\nTotal page faults: %d", page_faults); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值