一种屏蔽系统下拉菜单的方式

一种屏蔽系统下拉菜单的方式

导语

Android操作系统下禁用通知栏下拉功能一般使用反射调用StatusBarManager类中函数实现,但该方式需应用具有系统权限。本文介绍的方式采用修改framework层,绕过系统权限检查的方式实现。

一、禁用通知栏下拉功能

查看系统源码: /frameworks/base/core/java/android/app/StatusBarManager.java

/**
 * Disable some features in the status bar.  Pass the bitwise-or of the DISABLE_flags.
 * To re-enable everything, pass {@link #DISABLE_NONE}.
 */
public void disable(int what) {
    try {
        final IStatusBarService svc = getService();
        if (svc != null) {
            svc.disable(what, mToken, mContext.getPackageName());
        }
   } catch (RemoteException ex) {
        // system process is dead anyway.
        throw new RuntimeException(ex);
    }
}

根据其中 disable 函数,采用反射方式禁用下拉菜单,源码如下:

public static final int STATUS_BAR_DISABLE_EXPAND = 0x00010000;

public static final void disableStatusBar(Context ctx) {

    Object sbservice = ctx.getSystemService("statusbar");

    try {
        Class statusBarManager = Class
                .forName("android.app.StatusBarManager");
        Method collapse;
        collapse = statusBarManager.getMethod("disable", int.class);
        collapse.invoke(sbservice,
                Integer.valueOf(STATUS_BAR_DISABLE_EXPAND));
    } catch (Exception e) {
        e.printStackTrace();
    }
}

但是实际调用时会抛出异常信息,如下图所示:

异常显示必须配置 android.Manifest.permission.STATUS_BAR 权限,但必须系统应用才能配置该权限。怎样绕过系统权限的检测呢,下面将进行介绍。

二、怎样绕过 android.Manifest.permission.STATUS_BAR 权限检测

继续查看源码,查找 StatusBarManager.javadisable 实现方式

发现 /frameworks/base/services/java/com/android/server/StatusBarManagerService.java 中有该函数的具体实现。

public void disable(int what, IBinder token, String pkg) {        
    enforceStatusBar();

    synchronized (mLock) {
        disableLocked(what, token, pkg);
    }
}

查看 enforceStatusBar 源码发现该函数,对 android.Manifest.permission.STATUS_BAR 权限进行了检测。

private void enforceStatusBar() {
    mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
            "StatusBarManagerService");
}

那么我们只要修改 disable 函数,取消其中关于 enforceStatusBar 调用,直接调用 disableLocked 函数禁用下拉通知,即可绕过权限的检测了。

三、framewok层修改

此步需要用到的工具:

baksmalismali。下载地址

1、adb 连接入手机,将 /system/framework/services.jar 文件考出进行修改,此步骤需要 ROOT 权限。

2、使用 baksmaliserviec.jar 进行反编译。命令:java -jar baksmali.jar -o OUTDIR services.jar

3、在反编译生成的 smali 文件中找到 StatusBarManagerService.smali 进行修改。此步需要对smali文件格式有一定的了解,可参照网上相关教程这里不再详解。

.method public disable(ILandroid/os/IBinder;Ljava/lang/String;)V
    .registers 6
    .param p1, "what"    # I
    .param p2, "token"    # Landroid/os/IBinder;
    .param p3, "pkg"    # Ljava/lang/String;

    .prologue
    .line 143
    invoke-direct {p0}, Lcom/android/server/StatusBarManagerService;->enforceStatusBar()V

    .line 145
    iget-object v1, p0, Lcom/android/server/StatusBarManagerService;->mLock:Ljava/lang/Object;

    monitor-enter v1

    .line 146
    :try_start_6
    invoke-direct {p0, p1, p2, p3}, Lcom/android/server/StatusBarManagerService;->disableLocked(ILandroid/os/IBinder;Ljava/lang/String;)V

    .line 147
    monitor-exit v1

    .line 148
    return-void

    .line 147
    :catchall_b
    move-exception v0

    monitor-exit v1
    :try_end_d
    .catchall {:try_start_6 .. :try_end_d} :catchall_b

    throw v0
.end method

其中第143行,就是对 enforceStatusBar 函数的调用,这里删除相关的调用即可。

    .line 143
    invoke-direct {p0}, Lcom/android/server/StatusBarManagerService;->enforceStatusBar()V

修改后的 disable 函数如下:

.method public disable(ILandroid/os/IBinder;Ljava/lang/String;)V
    .registers 6
    .param p1, "what"    # I
    .param p2, "token"    # Landroid/os/IBinder;
    .param p3, "pkg"    # Ljava/lang/String;

    .prologue
    .line 145
    iget-object v1, p0, Lcom/android/server/StatusBarManagerService;->mLock:Ljava/lang/Object;

    monitor-enter v1

    .line 146
    :try_start_6
    invoke-direct {p0, p1, p2, p3}, Lcom/android/server/StatusBarManagerService;->disableLocked(ILandroid/os/IBinder;Ljava/lang/String;)V

    .line 147
    monitor-exit v1

    .line 148
    return-void

    .line 147
    :catchall_b
    move-exception v0

    monitor-exit v1
    :try_end_d
    .catchall {:try_start_6 .. :try_end_d} :catchall_b

    throw v0
.end method

4、使用 smali 对修改后的文件进行编译。命令:java -jar smali.jar SRCDIR -o OUTDIR\classes.dex

5、用压缩方式打开 services.jar,将生成的 classes.dex 复制进去替换同名文件。

6、再将完成修改的 services.jar 文件复制到手机 /system/framework/ 目录并替换源文件,整个framework层的修改就完成了,替换后一定记得修改 services.jar 文件权限并重启手机,默认权限为644。

四、结语

修改后使用之前反射的方式调用 disable 函数就不会再抛出异常,而且下拉栏也被成功禁用。

本文主要提供了一种绕过权限检测,禁用下拉菜单的思路,针对4.0以上的大多数系统都能完美实现。大家也可以根据该思路实现其他需要 framework 层修改的功能,具体实现就需要查阅相关系统源码了。

你可能感兴趣的:(一种屏蔽系统下拉菜单的方式)