Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: Android系统 自定义开机广播,禁止后台服务,运行手动安装应用接收开机广播

Android 高版本引入了一些限制和变化,不像以前7.1以下的方便,对我们客制化搬砖效率和用户都有一定的影响。例如,Android 8+限制了后台应用启动活动的能力,增加了后台位置访问权限的要求,以及禁止了手动安装的应用在未打开的情况下接收开机广播。

本文将介绍如何通过修改Android源码来实现以下三个目标:

  • 自定义开机广播:在系统启动完成后发送一个自定义的广播,让自定义的应用可以接收并执行相应的操作。
  • 禁止后台服务:取消对后台应用启动服务的限制,让任何应用都可以在后台运行服务。
  • 运行手动安装应用接收开机广播:允许手动安装的应用在未打开的情况下接收系统的开机广播,让它们可以在开机后自动启动。

自定义开机广播

背景知识

开机广播是一种特殊的系统广播,它在系统启动完成后发送给所有注册了android.intent.action.BOOT_COMPLETED过滤器的应用。开机广播可以让应用在开机后执行一些初始化或定期的任务,例如更新数据,启动服务,设置闹钟等。

修改方法

要实现自定义开机广播,我们需要修改两个文件:

  • frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:这个文件是ActivityManagerService类的源码,它负责管理系统中所有活动、进程、服务和广播等组件。我们需要修改它的broadcastIntentLocked方法,这个方法是用来发送广播的核心方法。
  • frameworks/base/services/core/java/com/android/server/am/UserController.java:这个文件是UserController类的源码,它负责管理系统中所有用户和用户相关的操作。我们需要修改它的finishUserUnlockedCompleted方法,这个方法是在用户解锁完成后调用的。

具体的修改步骤如下:

  1. ActivityManagerService.java中找到broadcastIntentLocked方法,在第15846行添加一行代码:
|| "com.ln28.intent.action.BOOT_COMPLETED".equals(action)

这样就可以让我们自定义的开机广播通过系统的保护检查,不被拒绝发送。

  1. 在同一个文件中,在第15906行注释掉以下代码:
if (callerApp != null) {
    Log.wtf(TAG, "Sending non-protected broadcast " + action
                    + " from system " + callerApp.toShortString() + " pkg " + callerPackage,
            new Throwable());
} else {
    Log.wtf(TAG, "Sending non-protected broadcast " + action
                    + " from system uid " + UserHandle.formatUid(callingUid)
                    + " pkg " + callerPackage,
            new Throwable());
}

这样就可以避免发送我们自定义的开机广播时产生不必要的警告日志。

  1. UserController.java中找到finishUserUnlockedCompleted方法,在第729行添加以下代码:
///ln28 add custom broadcast cast  
final Intent custombootIntent = new Intent("com.ln28.intent.action.BOOT_COMPLETED", null);
custombootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
custombootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
            | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
            | Intent.FLAG_RECEIVER_OFFLOAD);
final int callinguid = Binder.getCallingUid();
final int callingpid = Binder.getCallingPid();
FgThread.getHandler().post(() -> {
    mInjector.loadUserRecents(userId);
});
FgThread.getHandler().post(() -> {
    mInjector.broadcastIntent(custombootIntent,
            null, null, 0, null, null,
            null, AppOpsManager.OP_NONE,
            null, true, false, MY_PID, SYSTEM_UID, callinguid,
            callingpid, userId);
}); 
///ln28 add custom broadcast cast

这样就可以在用户解锁完成后发送我们自定义的开机广播,其中com.ln28.intent.action.BOOT_COMPLETED是我们自定义的广播的动作,userId是当前用户的ID,callinguidcallingpid是调用者的UID和PID,MY_PIDSYSTEM_UID是系统的PID和UID,其他参数可以参考broadcastIntentLocked方法的注释。

修改效果

修改完成后,我们需要重新编译并刷入系统。可以在任何应用中注册一个广播接收器,用来接收我们自定义的开机广播。例如,我们可以在AndroidManifest.xml中添加以下代码:

<receiver android:name=".CustomBootReceiver">
    <intent-filter>
        <action android:name="com.ln28.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

然后,在CustomBootReceiver类中实现onReceive方法,用来处理我们自定义的开机广播。例如,我们可以在onReceive方法中打印一条日志:

public class CustomBootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("CustomBootReceiver", "Received custom boot completed broadcast");
    }
}

这样,当我们开机并解锁后,就可以在日志中看到以下信息:

08-07 17:00:11.062  1229  1229 D CustomBootReceiver: Received custom boot completed broadcast

这说明我们成功地实现了自定义开机广播的功能。

注意: 测试发现自定义开机广播比系统自带的开机广播 要早1分钟!!

禁止后台服务和

背景知识

后台服务是一种在后台运行的组件,它可以执行一些不需要用户交互的长时间运行的任务。后台服务通常通过调用startServicebindService方法来启动。

但是,从Android 8.0(API级别26)开始,系统对后台服务的启动做了一些限制。具体来说,当应用处于后台时(即没有任何可见的活动),它不能直接启动服务。如果它尝试这样做,系统会抛出一个IllegalStateException异常,并显示以下错误信息:

java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.xxx/.MyService }: app is in background uid UidRecord{...}

为了避免这个异常,应用需要使用以下两种方式之一来启动服务:

  • 使用前台服务:前台服务是一种显示一个通知栏图标的服务,它表明该服务正在执行一些用户关心的操作。要使用前台服务,应用需要在服务启动后调用startForeground方法,并传递一个有效的通知对象。
  • 使用作业调度器:作业调度器是一种让应用在满足一定条件时执行一些任务的机制。要使用作业调度器,应用需要创建一个继承自JobService的类,并在其中实现任务的逻辑。然后,应用需要使用JobScheduler类来创建一个JobInfo对象,并指定任务的触发条件和执行策略。最后,应用需要使用schedule方法来提交任务给系统

修改方法

要实现禁止后台服务的功能,我们只需要修改一个文件:

  • frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:这个文件是ActivityManagerService类的源码,它负责管理系统中所有活动、进程、服务和广播等组件。我们需要修改它的appRestrictedInBackgroundLocked方法,这个方法是用来检查应用是否可以在后台启动服务的。

具体的修改步骤如下:

  1. ActivityManagerService.java中找到appRestrictedInBackgroundLocked方法,在第6275行注释掉以下代码:
if (packageTargetSdk >= Build.VERSION_CODES.O) {
    if (DEBUG_BACKGROUND_CHECK) {
        Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
    }
    return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}

这样就可以取消对目标SDK为O+的应用的后台服务启动限制。

修改效果

修改完成后,我们需要重新编译并刷入系统。然后,我们可以在任何应用中创建一个后台服务,并在AndroidManifest.xml中声明它。例如,我们可以创建一个MyService类,继承自Service,并在其中打印一条日志:

public class MyService extends Service {
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d("MyService", "Service started");
        return START_STICKY;
    }
}

然后,在AndroidManifest.xml中添加以下代码:

<service android:name=".MyService" />

这样,当我们在应用中调用以下代码时:

startService(new Intent(this, MyService.class));

就可以在日志中看到以下信息:

08-07 17:41:14.125  1229  1229 D MyService: Service started

这说明我们成功地实现了禁止后台服务的功能。

运行手动安装应用接收开机广播

背景知识

手动安装应用是指通过非官方渠道(例如APK文件)安装的应用,它们通常不受系统的信任和管理。手动安装应用在Android 11中受到了一些限制,例如不能在后台访问剪贴板,不能请求敏感权限,以及不能在未打开的情况下接收开机广播。

开机广播是一种特殊的系统广播,它在系统启动完成后发送给所有注册了android.intent.action.BOOT_COMPLETED过滤器的应用。开机广播可以让应用在开机后执行一些初始化或定期的任务,例如更新数据,启动服务,设置闹钟等。

修改方法

要实现运行手动安装应用接收开机广播的功能,我们需要修改一个文件:

  • frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java:这个文件是ActivityManagerService类的源码,它负责管理系统中所有活动、进程、服务和广播等组件。

具体的修改步骤如下:

  1. 在同一个文件中,在第15957行注释掉以下代码:
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

并在下一行添加以下代码:

intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);

这样就可以让后台服务启动时发送的广播包含已停止的应用,让它们可以接收到广播并启动服务。

这样就可以让所有应用都不受安装来源的限制,无论它们是不是即时应用。

修改效果

修改完成后,我们需要重新编译并刷入系统。可以在任何手动安装的应用中注册一个广播接收器,用来接收系统的开机广播。例如,我们可以在AndroidManifest.xml中添加以下代码:

<receiver android:name=".BootReceiver">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
    </intent-filter>
</receiver>

然后,在BootReceiver类中实现onReceive方法,用来处理系统的开机广播。例如,我们可以在onReceive方法中打印一条日志:

public class BootReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("SystemBootReceiver", "Received boot completed broadcast");
    }
}

这样,当我们开机并解锁后,就可以在日志中看到以下信息:

08-07 17:01:14.175  1229  1229 D SystemBootReceiver: Received system boot completed broadcast

这说明我们成功地实现了运行手动安装应用接收开机广播的功能。

总结

本文介绍了如何通过修改Android源码来实现三个目标:

  • 自定义开机广播:在系统启动完成后发送一个自定义的广播,让感兴趣的应用可以接收并执行相应的操作。
  • 禁止后台服务:取消对后台应用启动服务的限制,让任何应用都可以在后台运行服务。
  • 运行手动安装应用接收开机广播:允许手动安装的应用在未打开的情况下接收系统的开机广播,让它们可以在开机后自动启动。
相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
1月前
|
人工智能 搜索推荐 物联网
Android系统版本演进与未来展望####
本文深入探讨了Android操作系统从诞生至今的发展历程,详细阐述了其关键版本迭代带来的创新特性、用户体验提升及对全球移动生态系统的影响。通过对Android历史版本的回顾与分析,本文旨在揭示其成功背后的驱动力,并展望未来Android可能的发展趋势与面临的挑战,为读者呈现一个既全面又具深度的技术视角。 ####
|
1月前
|
IDE Java 开发工具
移动应用与系统:探索Android开发之旅
在这篇文章中,我们将深入探讨Android开发的各个方面,从基础知识到高级技术。我们将通过代码示例和案例分析,帮助读者更好地理解和掌握Android开发。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的信息和技巧。让我们一起开启Android开发的旅程吧!
|
25天前
|
监控 Java Android开发
深入探索Android系统的内存管理机制
本文旨在全面解析Android系统的内存管理机制,包括其工作原理、常见问题及其解决方案。通过对Android内存模型的深入分析,本文将帮助开发者更好地理解内存分配、回收以及优化策略,从而提高应用性能和用户体验。
|
26天前
|
存储 安全 Android开发
探索Android系统的最新安全特性
在数字时代,智能手机已成为我们生活中不可或缺的一部分。随着技术的不断进步,手机操作系统的安全性也越来越受到重视。本文将深入探讨Android系统最新的安全特性,包括其设计理念、实施方式以及对用户的影响。通过分析这些安全措施如何保护用户免受恶意软件和网络攻击的威胁,我们希望为读者提供对Android安全性的全面了解。
|
1月前
|
安全 Android开发 iOS开发
深入探讨Android与iOS系统的差异及未来发展趋势
本文旨在深入分析Android和iOS两大移动操作系统的核心技术差异、用户体验以及各自的市场表现,进一步探讨它们在未来技术革新中可能的发展方向。通过对比两者的开放性、安全性、生态系统等方面,本文揭示了两大系统在移动设备市场中的竞争态势和潜在变革。
|
Java Android开发 C++
Android应用程序安装过程源代码分析
转自 :http://blog.csdn.net/luoshengyang/article/details/6766010 Android系统在启动的过程中,会启动一个应用程序管理服务PackageManagerService,这个服务负责扫描系统中特定的目录,找到里面的应用程序文件,即以Apk为后缀的文件,然后对这些文件进解析,得到应用程序的相关信息,完成应用程序的安装过程
1307 0