Android之使用NotificationListenerService使得自己的应用不被杀及其源码分析

使用NotificationListenerService需要用户手动授权,该服务主要是获取系统通知的相关信息,这里只分析应用为什么不会被杀,使用通知内容这里不做分析。

NotificationListenerService的使用需要三步:

1.写一个类继承NotificationListenerService:

public class NotificationService extends NotificationListenerService {

    @Override
    public void onListenerConnected() {
        System.out.println("zyf onListenerConnected");
        super.onListenerConnected();
    }
    
    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        System.out.println("zyf onNotificationPosted");
        super.onNotificationPosted(sbn);
    }
}

2.在AndroidManifest.xml中注册该服务并声明相关权限:

<service
    android:name="com.example.notification.NotificationService"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>

3.开启监听通知的功能:

这一步需要用户手动授权,在“Settings” > “Security” > “Notification access”中,引导用户勾选自己的应用程序。此时服务连接成功、收到通知时就会有相应的log打出了。设置界面并不好找,所以可以在代码中帮助用户跳转到设置界面,如果服务没有被授权则跳转到设置界面:

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        String string = Settings.Secure.getString(getContentResolver(),
                "enabled_notification_listeners");
        System.out.println("zyf 已经允许使用通知权的应用:" + string);
        // 数据库中保存的格式:包名/服务名:包名/服务名,如:
        // com.example.notification/com.example.notification.NotificationService
        // :com.example.smartface/com.example.smartface.notification.SmartFaceListenerService
        if (!string.contains(NotificationService.class.getName())) {
            startActivity(new Intent(
                    "android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
        }
    }

}

到这里,只要用户授权,你的应用程序就不会被杀了。很简单吧,下面分析为什么不会被杀:

先看下NotificationListenerService服务的启动,总共就三种启动该服务的途径,分别是接收到PACKAGE相关的广播(安装、更新、卸载等)触发启动、多用户之间的切换触发启动、数据库变化触发启动。

接收到PACKAGE相关的广播触发启动:

开机时,会进行NotificationManagerService服务的初始化操作:

public NotificationManagerService(Context context) {
    super(context);
}

@Override
public void onStart() {
    . . .
    // 初始化NotificationListeners,它是ManagedServices的子类
    mListeners = new NotificationListeners();
    . . .

    // 注册接收PACKAGE相关的广播
    IntentFilter pkgFilter = new IntentFilter();
    pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
    pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    pkgFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
    pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
    pkgFilter.addDataScheme("package");
    getContext().registerReceiverAsUser(mPackageIntentReceiver, UserHandle.ALL, pkgFilter, null,
            null);
    . . .
    // 发布服务到系统
    publishBinderService(Context.NOTIFICATION_SERVICE, mService);
    . . .
}

// 接收PACKAGE相关的广播
private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action == null) {
            return;
        }
        . . .
        if (action.equals(Intent.ACTION_PACKAGE_ADDED)
                || (queryRemove=action.equals(Intent.ACTION_PACKAGE_REMOVED))
                || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
                || (packageChanged=action.equals(Intent.ACTION_PACKAGE_CHANGED))
                || (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
                || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
            . . .
			// 接收到广播后回调mListeners的onPackagesChanged方法
            mListeners.onPackagesChanged(queryReplace, pkgList);
			. . .
        }
    }
};

下面看下ManagedServices类的onPackagesChanged方法:

public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
    if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
            + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
            + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
    boolean anyServicesInvolved = false;
    if (pkgList != null && (pkgList.length > 0)) {
        for (String pkgName : pkgList) {
		    // mEnabledServicesPackageNames中保存的是从数据库中查询到的经过用户授权的应用包名
            if (mEnabledServicesPackageNames.contains(pkgName)) {
                anyServicesInvolved = true;
            }
        }
    }

    if (anyServicesInvolved) {
        // if we're not replacing a package, clean up orphaned bits
        if (!queryReplace) {
            disableNonexistentServices();
        }
        // 重新绑定所有经过授权的服务
        rebindServices();
    }
}

/**
 * Called whenever packages change, the user switches, or the secure setting
 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
 */
 // 重新绑定所有经过授权的服务
private void rebindServices() {

    // 取出所有经过授权的服务
    . . .

    for (ManagedServiceInfo info : toRemove) {
        final ComponentName component = info.component;
        final int oldUser = info.userid;
        Slog.v(TAG, "disabling " + getCaption() + " for user "
                + oldUser + ": " + component);
		// 注销服务
        unregisterService(component, info.userid);
    }

    for (int i = 0; i < nUserIds; ++i) {
        final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
        final int N = add.size();
        for (int j = 0; j < N; j++) {
            final ComponentName component = add.get(j);
            Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
                    + component);
		    // 根据组件名重新绑定服务
            registerService(component, userIds[i]);
        }
    }

    mLastSeenProfileIds = mUserProfiles.getCurrentProfileIds();
}

// 绑定服务
private void registerService(final ComponentName name, final int userid) {
    if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);

    synchronized (mMutex) {
        . . .

        Intent intent = new Intent(mConfig.serviceInterface);
        intent.setComponent(name);
        . . .

        try {
            if (DEBUG) Slog.v(TAG, "binding: " + intent);
			// 绑定服务
            if (!mContext.bindServiceAsUser(intent,
                    new ServiceConnection() {
                        IInterface mService;

                        @Override
                        public void onServiceConnected(ComponentName name, IBinder binder) {
                            boolean added = false;
                            ManagedServiceInfo info = null;
                            synchronized (mMutex) {
                                mServicesBinding.remove(servicesBindingTag);
                                try {
                                    mService = asInterface(binder);
                                    info = newServiceInfo(mService, name,
                                            userid, false /*isSystem*/, this, targetSdkVersion);
                                    binder.linkToDeath(info, 0);
                                    added = mServices.add(info);
                                } catch (RemoteException e) {
                                    // already dead
                                }
                            }
                            if (added) {
                                onServiceAdded(info);
                            }
                        }

                        @Override
                        public void onServiceDisconnected(ComponentName name) {
                            Slog.v(TAG, getCaption() + " connection lost: " + name);
                        }
                    },
                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
                    new UserHandle(userid)))
            {
                mServicesBinding.remove(servicesBindingTag);
                Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
                return;
            }
        } catch (SecurityException ex) {
            Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
            return;
        }
    }
}

到这里,服务就启动起来了。

多用户之间的切换触发启动:

// 用户切换
public void onUserSwitched(int user) {
    if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
    if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
        if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
        return;
    }
	// 重新绑定经过授权的服务
    rebindServices();
}

数据库变化触发启动:

public ManagedServices(Context context, Handler handler, Object mutex,
        UserProfiles userProfiles) {
    . . .
    mSettingsObserver = new SettingsObserver(handler);
	. . .
}

// 手机启动后注册监听
public void onBootPhaseAppsCanStart() {
    // 注册数据库监听
    mSettingsObserver.observe();
}

// 监听数据库变化
private class SettingsObserver extends ContentObserver {
    private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);

    private SettingsObserver(Handler handler) {
        super(handler);
    }

    // 注册数据库监听
    private void observe() {
        ContentResolver resolver = mContext.getContentResolver();
        resolver.registerContentObserver(mSecureSettingsUri,
                false, this, UserHandle.USER_ALL);
        update(null);
    }

    @Override
    public void onChange(boolean selfChange, Uri uri) {
        update(uri);
    }

    private void update(Uri uri) {
        if (uri == null || mSecureSettingsUri.equals(uri)) {
            if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
                    " / uri=" + uri);
            // 数据库变化时重新绑定所有授权的服务
            rebindServices();
        }
    }
}

到这里三种触发启动的方式都分析完了,但是好像还看不出应用为什么不会被杀。

系统杀应用的两种方式:killApplicationProcess和forceStopPackage

上面两种方法都是系统方法,故需要使用Binder代理对象和反射的方法来调用:

public class KillForceStopManager {

    private Method mKill;
    private Method mForceStop;
    private Object mActivityManagerNative;

    public KillForceStopManager() {
        try {
            Method getDefault = Class.forName(
                    "android.app.ActivityManagerNative").getDeclaredMethod(
                    "getDefault", new Class[] {});
            mActivityManagerNative = getDefault.invoke(null, new Object[] {});
            mKill = mActivityManagerNative.getClass().getDeclaredMethod(
                    "killApplicationProcess", String.class, int.class);
            mForceStop = mActivityManagerNative.getClass().getDeclaredMethod(
                    "forceStopPackage", String.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 只有系统应用才有kill的权限,故这里传递的uid是1000
    public void killApplicationProcess(String processName) {
        killApplicationProcess(processName, 1000);
    }

    private void killApplicationProcess(String processName, int processUid) {
        if (mKill != null) {
            try {
                mKill.invoke(mActivityManagerNative, processName, processUid);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void forceStopPackage(String pkgName) {
        if (mForceStop != null) {
            try {
                mForceStop.invoke(mActivityManagerNative, pkgName);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

上面只是介绍了两种方法的使用方式,下面具体分析下两种方式的区别,这两个方法的具体实现都是在ActivityManagerService类中:

@Override
public void killApplicationProcess(String processName, int uid) {
    if (processName == null) {
        return;
    }

    int callerUid = Binder.getCallingUid();
    // 只有系统进程能kill应用程序
    if (callerUid == Process.SYSTEM_UID) {
        synchronized (this) {
            // 根据进程名获取进程
            ProcessRecord app = getProcessRecordLocked(processName, uid, true);
            if (app != null && app.thread != null) {
                try {
                    // 通过Binder对象调用scheduleSuicide方法执行自杀操作
                    app.thread.scheduleSuicide();
                } catch (RemoteException e) {
                    // If the other end already died, then our work here is done.
                }
            } else {
                Slog.w(TAG, "Process/uid not found attempting kill of "
                        + processName + " / " + uid);
            }
        }
    } else {
        throw new SecurityException(callerUid + " cannot kill app process: " +
                processName);
    }
}

通过Binder代理对象最后调用到ActivityThread类中内部类ApplicationThread类的scheduleSuicide方法:

public final void scheduleSuicide() {
    sendMessage(H.SUICIDE, null);
}

private class H extends Handler {
    . . .
    public static final int SUICIDE                 = 130;
    . . .
    public void handleMessage(Message msg) {
        switch (msg.what) {
            . . .
            case SUICIDE:
                Process.killProcess(Process.myPid());
                break;
            . . .
        }
        . . .
    }
    . . .
}

下面看下Process类的killProcess方法:

public static final int SIGNAL_KILL = 9;

public static final void killProcess(int pid) {
    sendSignal(pid, SIGNAL_KILL);
}

public static final native void sendSignal(int pid, int signal);

kill杀应用时,系统会调用ActiveServices类的killServicesLocked(ProcessRecord app, boolean allowRestart)方法,允许服务重启,即服务杀不死。

下面分析forceStopPackage方法:

@Override
public void forceStopPackage(final String packageName, int userId) {
    // forceStopPackage杀应用需要FORCE_STOP_PACKAGES权限
    if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
            != PackageManager.PERMISSION_GRANTED) {
        . . .
    }
    . . .
    try {
        IPackageManager pm = AppGlobals.getPackageManager();
        synchronized(this) {
            int[] users = userId == UserHandle.USER_ALL
                    ? getUsersLocked() : new int[] { userId };
            for (int user : users) {
                . . .
                try {
                    // 设置应用为停止运行状态,第一次安装应用时也调用过该方法
                    pm.setPackageStoppedState(packageName, true, user);
                } catch (RemoteException e) {
                } catch (IllegalArgumentException e) {
                    Slog.w(TAG, "Failed trying to unstop package "
                            + packageName + ": " + e);
                }
                if (isUserRunningLocked(user, false)) {
                    // 杀应用后发送广播
                    forceStopPackageLocked(packageName, pkgUid, "from pid " + callingPid);
                }
            }
        }
    } finally {
        Binder.restoreCallingIdentity(callingId);
    }
}

// 杀应用后发送广播
private void forceStopPackageLocked(final String packageName, int uid, String reason) {
    // 杀应用
    forceStopPackageLocked(packageName, UserHandle.getAppId(uid), false,
            false, true, false, false, UserHandle.getUserId(uid), reason);
    // 创建Action为ACTION_PACKAGE_RESTARTED的intent
    Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
            Uri.fromParts("package", packageName, null));
    if (!mProcessesReady) {
        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                | Intent.FLAG_RECEIVER_FOREGROUND);
    }
    intent.putExtra(Intent.EXTRA_UID, uid);
    intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
    // 发送intent所描述的广播,广播的发送过程前面有文章已经分析过
    broadcastIntentLocked(null, null, intent,
            null, null, 0, null, null, null, AppOpsManager.OP_NONE,
            null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid));
}

// 杀应用
private final boolean forceStopPackageLocked(String packageName, int appId,
        boolean callerWillRestart, boolean purgeCache, boolean doit,
        boolean evenPersistent, boolean uninstalling, int userId, String reason) {
    . . .

    // 杀应用进程
    boolean didSomething = killPackageProcessesLocked(packageName, appId, userId,
            -100, callerWillRestart, true, doit, evenPersistent,
            packageName == null ? ("stop user " + userId) : ("stop " + packageName));

    // 结束应用所有Activity
    if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
            packageName, null, doit, evenPersistent, userId)) {
        if (!doit) {
            return true;
        }
        didSomething = true;
    }

    // 结束应用所有Service
    if (mServices.bringDownDisabledPackageServicesLocked(
            packageName, null, userId, evenPersistent, true, doit)) {
        if (!doit) {
            return true;
        }
        didSomething = true;
    }
    . . .

    // 结束应用所有Provider
    ArrayList<ContentProviderRecord> providers = new ArrayList<>();
    if (mProviderMap.collectPackageProvidersLocked(packageName, null, doit, evenPersistent,
            userId, providers)) {
        if (!doit) {
            return true;
        }
        didSomething = true;
    }
    for (i = providers.size() - 1; i >= 0; i--) {
        removeDyingProviderLocked(null, providers.get(i), true);
    }

    // Remove transient permissions granted from/to this package/user
    removeUriPermissionsForPackageLocked(packageName, userId, false);

    // 结束应用所有广播
    if (doit) {
        for (i = mBroadcastQueues.length - 1; i >= 0; i--) {
            didSomething |= mBroadcastQueues[i].cleanupDisabledPackageReceiversLocked(
                    packageName, null, userId, doit);
        }
    }

    . . .

    return didSomething;
}

到这里终于知道应用为什么杀不死了,因为forceStop杀死应用后会发送PACKAGE相关的广播,而接收到这个广播后NotificationManagerService又会重新启动所有用户授权的服务,故实现了NotificationListenerService服务的Service是杀不死的。

    原文作者:张永飞
    原文地址: https://blog.csdn.net/zhangyongfeiyong/article/details/52279742
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞