• Android 侦听应用(Package)变化的方法侦听广播


    应用的状态变化,包括安装、卸载、更新,是android系统上重要的事件。如何侦听到?有两种方法,一是通过侦听广播,一是实现PackageMonitor。

    侦听广播
     
    当Package状态发生变化时,系统会广播如下一些Action的Intent:

    应用安装:
    public static final String ACTION_PACKAGE_ADDED = "android.intent.action.PACKAGE_ADDED";

    应用更新:
    public static final String ACTION_PACKAGE_REPLACED = "android.intent.action.PACKAGE_REPLACED";
    应用的新版本替代旧版本被安装
    public static final String ACTION_MY_PACKAGE_REPLACED = "android.intent.action.MY_PACKAGE_REPLACED";
    应用的新版本替代旧版本被安装,只发给被更新的应用自己
    public static final String ACTION_PACKAGE_CHANGED = "android.intent.action.PACKAGE_CHANGED";
    应用被改变,譬如某些组件被disable/enable

    应用卸载:
    public static final String ACTION_PACKAGE_REMOVED = "android.intent.action.PACKAGE_REMOVED";
    应用被卸载时发出,正在被卸载的应用自身不会收到
    public static final String ACTION_PACKAGE_FULLY_REMOVED = "android.intent.action.PACKAGE_FULLY_REMOVED";
    应用被完全卸载时发出(数据被删除)
     
    上述Intent都为保护型,只能够由系统发出。
     
    针对上述定义,结合android源代码,研究几个问题。Android对于Package的管理主要逻辑在PackageManagerService(PMS)中,主要在这个类中研究上述问题:
     
    (1)系统如何实现只发给某个应用?

    ACTION_MY_PACKAGE_REPLACED是如何处理的?

    private void sendSystemPackageUpdatedBroadcastsInternal() {
        Bundle extras = new Bundle(2);
        extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
        extras.putBoolean(Intent.EXTRA_REPLACING, true);
        sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, removedPackage,
                extras, 0, null, null, null);
        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, removedPackage,
                extras, 0, null, null, null);
        sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null,
                null, 0, removedPackage, null, null);
    }
    
    final void sendPackageBroadcast(final String action, final String pkg, final Bundle extras,
            final int flags, final String targetPkg, final IIntentReceiver finishedReceiver,
            final int[] userIds) {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                try {
                    final IActivityManager am = ActivityManagerNative.getDefault();
                    if (am == null) return;
                    final int[] resolvedUserIds;
                    if (userIds == null) {
                        resolvedUserIds = am.getRunningUserIds();
                    } else {
                        resolvedUserIds = userIds;
                    }
                    for (int id : resolvedUserIds) {
                        final Intent intent = new Intent(action,
                                pkg != null ? Uri.fromParts(PACKAGE_SCHEME, pkg, null) : null);
                        if (extras != null) {
                            intent.putExtras(extras);
                        }
                        if (targetPkg != null) {
                            intent.setPackage(targetPkg);
                        }
                        // Modify the UID when posting to other users
                        int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
                        if (uid > 0 && UserHandle.getUserId(uid) != id) {
                            uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
                            intent.putExtra(Intent.EXTRA_UID, uid);
                        }
                        intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | flags);
                        if (DEBUG_BROADCASTS) {
                            RuntimeException here = new RuntimeException("here");
                            here.fillInStackTrace();
                            Slog.d(TAG, "Sending to user " + id + ": "
                                    + intent.toShortString(false, true, false, false)
                                    + " " + intent.getExtras(), here);
                        }
                        am.broadcastIntent(null, intent, null, finishedReceiver,
                                0, null, null, null, android.app.AppOpsManager.OP_NONE,
                                null, finishedReceiver != null, false, id);
                    }
                } catch (RemoteException ex) {
                }
            }
        });
    }
    看到在广播ACTION_MY_PACKAGE_REPLACED的时候,是通过Intent.setPackage(String packageName)实现定向发送。
    (2)ACTION_PACKAGE_CHANGED在什么场景下使用?

    ACTION_PACKAGE_CHANGED在PMS中只有一处使用入口:

    private void sendPackageChangedBroadcast(String packageName,
            boolean killFlag, ArrayList<String> componentNames, int packageUid) {
        if (DEBUG_INSTALL)
            Log.v(TAG, "Sending package changed: package=" + packageName + " components="
                    + componentNames);
        Bundle extras = new Bundle(4);
        extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
        String nameList[] = new String[componentNames.size()];
        componentNames.toArray(nameList);
        extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
        extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);
        extras.putInt(Intent.EXTRA_UID, packageUid);
        // If this is not reporting a change of the overall package, then only send it
        // to registered receivers.  We don't want to launch a swath of apps for every
        // little component state change.
        final int flags = !componentNames.contains(packageName)
                ? Intent.FLAG_RECEIVER_REGISTERED_ONLY : 0;
        sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED,  packageName, extras, flags, null, null,
                new int[] {UserHandle.getUserId(packageUid)});
    }
    追踪sendPackageChangedBroadcast()的调用,来自setComponentEnabledSetting()。

    这是实现PackageManager的对外公开API,看一下PackageManager中对此的定义:

    /**
     * Set the enabled setting for a package component (activity, receiver, service, provider).
     * This setting will override any enabled state which may have been set by the component in its
     * manifest.
     *
     * @param componentName The component to enable
     * @param newState The new enabled state for the component.  The legal values for this state
     *                 are:
     *                   {@link #COMPONENT_ENABLED_STATE_ENABLED},
     *                   {@link #COMPONENT_ENABLED_STATE_DISABLED}
     *                   and
     *                   {@link #COMPONENT_ENABLED_STATE_DEFAULT}
     *                 The last one removes the setting, thereby restoring the component's state to
     *                 whatever was set in it's manifest (or enabled, by default).
     * @param flags Optional behavior flags: {@link #DONT_KILL_APP} or 0.
     */
    public abstract void setComponentEnabledSetting(ComponentName componentName,
            int newState, int flags);

    这是PackageManager提供的修改四大控件enable/disable的API,当然调用是需要检查权限的,此处不展开介绍。

    (3)ACTION_PACKAGE_REMOVED和ACTION_PACKAGE_FULLY_REMOVED的逻辑关系

    查看这两个Action在PMS中的使用,发现只有一处:

    private void sendPackageRemovedBroadcastInternal(boolean killApp) {
        Bundle extras = new Bundle(2);
        extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
        extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
        extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
        if (isUpdate || isRemovedPackageSystemUpdate) {
            extras.putBoolean(Intent.EXTRA_REPLACING, true);
        }
        extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
        if (removedPackage != null) {
            sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
                    extras, 0, null, null, removedUsers);
            if (dataRemoved && !isRemovedPackageSystemUpdate) {
                sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED,
                        removedPackage, extras, 0, null, null, removedUsers);
            }
        }
        if (removedAppId >= 0) {
            sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, 0, null, null,
                    removedUsers);
        }
    }

    看到Package removed发生时,会发ACTION_PACKAGE_REMOVED;并且只有在数据被删除且非删除系统更新的app时,才会发送ACTION_PACKAGE_FULLY_REMOVED。在PackageManager中有一个flag常量定义PackageManager.DELETE_KEEP_DATA,用以决定在删除app时是否保留数据。

  • 相关阅读:
    [例程]string.trim().length()的用法
    用各种look and feel打造swing界面
    深入浅出Java多线程(1)方法 join
    eclipse中cvs使用配置
    什么时候用Vector, 什么时候改用ArrayList?
    array,vertor,arraylist,hashable,hashmap等几个易混淆概念的区别
    java.lang.Class.getResource()这哥个方法主要是做什么用
    织梦dedecms实现按照字母搜索的实现方法
    浅析JTable与TableModel、TableCellRenderer、TableCellEditor接口——使用JComboBox显示单元格的值
    用java –jar 命令运行Jar包
  • 原文地址:https://www.cnblogs.com/zhujiabin/p/7765116.html
Copyright © 2020-2023  润新知