`

在任务栏中清除掉播放器的进程,状态栏仍有音乐播放器状态,且音乐仍在后台播放

阅读更多
在任务栏中清除掉播放器的进程,状态栏仍有音乐播放器状态,且音乐仍在后台播放

1.先从UI切入问题分析,使用Monitor—Hierarchy View找到清除任务X按钮对应的id为r.id.dismiss_task,并且属于SystemUI

2.到SystemUI定位到包含dismiss_task的是TaskViewHeader.java,该按钮对应的onClick事件为:
TaskView tv = Utilities.findParent(this, TaskView.class);
            tv.dismissTask();

            // Keep track of deletions by the dismiss button
            MetricsLogger.histogram(getContext(), "overview_task_dismissed_source",
                    Constants.Metrics.DismissSourceHeaderButton);


3.查看TaskView.java中的dismissTask
void dismissTask() {
        // Animate out the view and call the callback
        final TaskView tv = this;
        DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv);
        dismissEvent.addPostAnimationCallback(new Runnable() {
            @Override
            public void run() {
                EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv,
                        new AnimationProps(TaskStackView.DEFAULT_SYNC_STACK_DURATION,
                                Interpolators.FAST_OUT_SLOW_IN)));
            }
        });
        EventBus.getDefault().send(dismissEvent);
    }

这里EventBus send一个DismissTaskViewEvent,处理完成会回调再发生一个TaskViewDismissedEvent

5.定位到处理DismissTaskViewEvent是在TaskStackView.java
    public final void onBusEvent(DismissTaskViewEvent event) {
        // For visible children, defer removing the task until after the animation
        mAnimationHelper.startDeleteTaskAnimation(
                event.taskView, useGridLayout(), event.getAnimationTrigger());
    }


处理TaskViewDismissedEvent
public final void onBusEvent(TaskViewDismissedEvent event) {
        // Announce for accessibility
        announceForAccessibility(getContext().getString(
                R.string.accessibility_recents_item_dismissed, event.task.title));

        if (useGridLayout() && event.animation != null) {
            event.animation.setListener(new AnimatorListenerAdapter() {
                public void onAnimationEnd(Animator animator) {
                    if (mTaskViewFocusFrame != null) {
                        // Resize the grid layout task view focus frame
                        mTaskViewFocusFrame.resize();
                    }
                }
            });
        }

        // Remove the task from the stack
        mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
        EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
        if (mStack.getTaskCount() > 0 && Recents.getConfiguration().isLowRamDevice) {
            EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
        }

        MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
                event.task.key.getComponent().toString());
    }


6.接着DeleteTaskDataEvent在RecentsActivity.java处理

public final void onBusEvent(DeleteTaskDataEvent event) {
        // Remove any stored data from the loader
        RecentsTaskLoader loader = Recents.getTaskLoader();
        loader.deleteTaskData(event.task, false);

        // Remove the task from activity manager
        SystemServicesProxy ssp = Recents.getSystemServices();
        ssp.removeTask(event.task.key.id);
    }


7.SystemServicesProxy.java中removeTask
 /** Removes the task */
    public void removeTask(final int taskId) {
        if (mAm == null) return;
        if (RecentsDebugFlags.Static.EnableMockTasks) return;

        // Remove the task.
        mUiOffloadThread.submit(() -> {
            mAm.removeTask(taskId);
        });
    }

这里就是关键代码了,通过调用ActivityManager的removeTask来删除任务

8.通过ActivityManager.java其对应的是ActivityManagerService.java
    @Override
    public boolean removeTask(int taskId) {
        enforceCallingPermission(android.Manifest.permission.REMOVE_TASKS, "removeTask()");
        synchronized (this) {
            final long ident = Binder.clearCallingIdentity();
            try {
                return mStackSupervisor.removeTaskByIdLocked(taskId, true, REMOVE_FROM_RECENTS);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }


9.ActivityStackSupervisor.java
    boolean removeTaskByIdLocked(int taskId, boolean killProcess, boolean removeFromRecents,
            boolean pauseImmediately) {
        final TaskRecord tr = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS,
                INVALID_STACK_ID);
        if (tr != null) {
            tr.removeTaskActivitiesLocked(pauseImmediately);
            cleanUpRemovedTaskLocked(tr, killProcess, removeFromRecents);
            if (tr.isPersistable) {
                mService.notifyTaskPersisterLocked(null, true);
            }
            return true;
        }
        Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);
        return false;
    }


 void cleanUpRemovedTaskLocked(TaskRecord tr, boolean killProcess, boolean removeFromRecents) {
        if (removeFromRecents) {
            mRecentTasks.remove(tr);
            tr.removedFromRecents();
        }
        ComponentName component = tr.getBaseIntent().getComponent();
        if (component == null) {
            Slog.w(TAG, "No component for base intent of task: " + tr);
            return;
        }

        // Find any running services associated with this app and stop if needed.
        mService.mServices.cleanUpRemovedTaskLocked(tr, component, new Intent(tr.getBaseIntent()));

        if (!killProcess) {
            return;
        }

        // Determine if the process(es) for this task should be killed.
        final String pkg = component.getPackageName();
        ArrayList<ProcessRecord> procsToKill = new ArrayList<>();
        ArrayMap<String, SparseArray<ProcessRecord>> pmap = mService.mProcessNames.getMap();
        for (int i = 0; i < pmap.size(); i++) {

            SparseArray<ProcessRecord> uids = pmap.valueAt(i);
            for (int j = 0; j < uids.size(); j++) {
                ProcessRecord proc = uids.valueAt(j);
                if (proc.userId != tr.userId) {
                    // Don't kill process for a different user.
                    continue;
                }
                if (proc == mService.mHomeProcess) {
                    // Don't kill the home process along with tasks from the same package.
                    continue;
                }
                if (!proc.pkgList.containsKey(pkg)) {
                    // Don't kill process that is not associated with this task.
                    continue;
                }

                for (int k = 0; k < proc.activities.size(); k++) {
                    TaskRecord otherTask = proc.activities.get(k).getTask();
                    if (tr.taskId != otherTask.taskId && otherTask.inRecents) {
                        // Don't kill process(es) that has an activity in a different task that is
                        // also in recents.
                        return;
                    }
                }

                if (proc.foregroundServices) {
                    // Don't kill process(es) with foreground service.
                    return;
                }

                // Add process to kill list.
                procsToKill.add(proc);
            }
        }

        // Kill the running processes.
        for (int i = 0; i < procsToKill.size(); i++) {
            ProcessRecord pr = procsToKill.get(i);
            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                    && pr.curReceivers.isEmpty()) {
                pr.kill("remove task", true);
            } else {
                // We delay killing processes that are not in the background or running a receiver.
                pr.waitingToKill = "remove task";
            }
        }
    }

通过上述定位会发现music app包含了前台的服务foregroundServices,所以其process不会被kill掉。这个是google原生设计的。
那解决该问题,我们可以增加判断如果是removeFromRecents 为true时将其包含foregroundServices也kill掉
分享到:
评论

相关推荐

    Android 11 修改最近任务栏无法kill正在播放的音乐.patch

    Android 11 修改最近任务栏无法kill正在播放的音乐

    vc++ 应用源码包_5

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_1

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_2

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_6

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 应用源码包_3

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    vc++ 开发实例源码包

    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...

    VISUAL C++MFC扩展编程实例(想学MFC的朋友一定不要错过)

    4.1 实例1:在工具栏中添加静态标识符 64 4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: ...

    一份很实用的MFC资料

    4.1 实例1:在工具栏中添加静态标识符 64 4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: ...

    Visual C++ MFC扩展编程实例.PDF

    4.1 实例1:在工具栏中添加静态标识符 64 4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: ...

    VISUAL C MFC扩展编程实例与源码

    4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: 主菜单状态栏中的标记 81 第5章 菜单...

    VISUAL C++MFC扩展编程实例

    4.1 实例1:在工具栏中添加静态标识符 64 4.2 实例2:在工具栏中添加动态标识符 71 4.3 实例3:只启动一个实例 75 4.4 实例4:创建对话框/MDI混合式 应用程序 77 4.5 实例5:在系统托盘中添加图标 79 4.6 实例6: ...

    1350多个精品易语言模块

    复件 状态栏控件.ec 复制目录.ec 复制目录模块.ec 复制目录模块 1.ec 复制目录模块copy_dir.ec 外挂作坊1.4.ec 外挂作坊1.40909.ec 外挂作坊1.5-第六 版.ec 外挂作坊1.5版.ec 外挂作坊1.8.ec 外挂作坊1.85.ec 外挂...

    新版Android开发教程.rar

    � A ndroid 在设计初期就考虑了与现其有业务的融合,改变以往从计算机为主改成从手机使用为导向。新 生应用如:G oogle 地图及其衍生应用、 GMail 、 GTalk 等。 � GPS 卫星导航功能,手机照相, MP3 ,蓝芽等均...

    王牌超级工具箱 v20.3.zip

    6.屏幕偷拍间谍:能够在后台每隔5分中进行屏幕偷拍,悄悄查看别人怎样使用我的电脑。 (九)系统工具 包括:1)系统维护工具;2)系统进程管理;3)系统垃圾清理:4)系统右键设置:5)系统配置程序等. 王牌超级工具...

    三星W629刷机平台

    三星伯爵W629升级成功:  共要分三步分别写入W629 AK22.bin w629_preload_aj04_0x5400000 Mento_gsm_AK19_R ev04 所有过程...在待机状态下输入147*12690*#进入工程模式,选择‘全部清除’进行主清除. OK!!

    API之网络函数---整理网络函数及功能

    GetPrivateProfileSection 获取指定小节(在.ini文件中)所有项名和值的一个列表 GetPrivateProfileString 为初始化文件中指定的条目取得字串 GetProfileInt 取得win.ini初始化文件中指定条目的一个整数值 ...

    McAfee 8.0 简体中文

    件夹进行访问的进程、禁止的文件操作以及在某人尝试访问阻挡的项目时应 采取的操作。 这些"访问保护"功能在防范入侵时非常有效。在病毒发作时,管理员可以 阻止对感染病毒区域的访问,直到发布新的 DAT。 ...

    WINRAR5.0正式注册版

    你可以在压缩对话框中使用 "RAR 5.0" 选项或命令行中 使用 -ma 开关创建 RAR 5.0 压缩文件。 较老的软件,包括老版本的 WinRAR,不能解压 RAR 5.0 压缩文件,所以如果你计划把 一个压缩文件发送给其他人,则需要...

    易语言 茶凉专用模块

    子程序 窗口禁止, 逻辑型, 公开, 在窗口中允许或禁止所有鼠标及键盘输入(成功返回真,失败返回假) .参数 窗口句柄, 整数型, , 欲禁止鼠标键盘输入的窗口或控件的句柄 .参数 是否禁止, 逻辑型, 可空, 默认为真:禁止 假...

Global site tag (gtag.js) - Google Analytics