`
anson_xu
  • 浏览: 509518 次
  • 性别: Icon_minigender_1
  • 来自: 惠州
社区版块
存档分类

Android的Launcher成为系统中第一个启动的,也是唯一的

阅读更多

Android的Launcher成为系统中第一个启动的,也是唯一的

 

如果你要定制一个Android系统,你想用你自己的Launcher(Home)作主界面来替换Android自己的Home,而且不希望用户安装的Launcher来替换掉你的Launcher.
我们可以通过修改Framework来实现这样的功能。

这里以Android2.1的源代码为例来实际说明。

1)首先了解一下Android的启动过程。
Android系统的启动先从Zygote开始启动,然后......(中间的过程就不说了).....一直到了SystemServer(framework)这个地方,看到这段代码:

/**
* This method is called from Zygote to initialize the system. This will cause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);

public static void main(String[] args) {
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}

// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

System.loadLibrary("android_servers");
init1(args);
}

public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}

从SystemServer的main函数开始启动各种服务。
首先启动init1,然后启动init2.
从上面的注释可以看到:init1这个方法时被Zygote调用来初始化系统的,init1会启动native的服务如SurfaceFlinger,AudioFlinger等等,这些工作做完以后会回调init2来启动Android的service。

这里我们主要来关注init2的过程。
init2中启动ServerThread线程,
ServerThread中启动了一系列的服务,比如这些:

ActivityManagerService
EntropyService
PowerManagerService
TelephonyRegistry
PackageManagerService
AccountManagerService
BatteryService
HardwareService
Watchdog
SensorService
BluetoothService
StatusBarService
ClipboardService
InputMethodManagerService
NetStatService
ConnectivityService
AccessibilityManagerService
NotificationManagerService
MountService
DeviceStorageMonitorService
LocationManagerService
SearchManagerService
FallbackCheckinService
WallpaperManagerService
AudioService
BackupManagerService
AppWidgetService

这些大大小小的服务起来以后,开始
((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady()
在systemReady后开始开始启动Launcher。

在寻找Launcher的时候是根据HOME的filter(在Manifest中定义的<category android:name="android.intent.category.HOME" />)来过滤。
然后根据filter出来的HOME来启动,如果只有一个HOME,则启动这个HOME,如果用户自己装了HOME,那就会弹出来一个列表供用户选择。

我们现在希望从这里弹出我们自己定制的Launcher,同时也不希望弹出选择HOME的界面,我们不希望用户修改我们的home,比如我们的home上放了好多广告,以及强制安装的程序,不希望用户把它干掉。

我们可以通过这样来实现:

2) 定义一个私有的filter选项,然后用这个选项来过滤HOME.
一般情况下我们使用Manifest中定义的<category android:name="android.intent.category.HOME"来过滤的,我们现在增加一个私有的HOME_FIRST过滤。

在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加两行代码

//lixinso:添加CATEGORY_HOME_FIRST
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_HOME_FIRST = "android.intent.category.HOME_FIRST";

3)修改和CATEGORY_HOME相关的所有的地方,都改成HOME_FIRST,主要是framework中的这几个地方:

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java中
//intent.addCategory(Intent.CATEGORY_HOME);
改成intent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso:
//if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
改成if (r.intent.hasCategory(Intent.CATEGORY_HOME_FIRST)) { //lixinso: Intent.CATEGORY_HOME -> Intent.CATEGORY_HOME_FIRST

frameworks/base/services/java/com/android/server/am/HistoryRecorder.java中
// _intent.hasCategory(Intent.CATEGORY_HOME) &&
改成 _intent.hasCategory(Intent.CATEGORY_HOME_FIRST) && //lixinso: Intent.CATEGORY_HOME->Intent.CATEGORY_HOME_FIRST

frameworks/policies/base/mid/com/android/internal/policy/impl/MidWindowManager.java中
//mHomeIntent.addCategory(Intent.CATEGORY_HOME);
改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

frameworks/policies/base/mid/com/android/internal/policy/impl/RecentApplicationsDialog.java中
//new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
改成 new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso

frameworks/policies/base/phone/com/android/internal/policy/impl/PhoneWindowManager.java中
//mHomeIntent.addCategory(Intent.CATEGORY_HOME);
改成 mHomeIntent.addCategory(Intent.CATEGORY_HOME_FIRST); //lixinso

frameworks/policies/base/phone/com/android/internal/policy/impl/RecentApplicationsDialog.java中
//ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),0);
改成 ResolveInfo homeInfo = pm.resolveActivity(new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME_FIRST),0); //lixinso

 

4) 写一个自己的Launcher.
可以参考android sample中的Launcher,或者android源代码中的 /packages/apps/Launcher 来写。
在Launcher中标记其是不是Launcher的最关键的代码时Manifest中的filter:android:name="android.intent.category.HOME"
现在我们定义了自己的filter,那么,我们在我们自己写的Launcher中将Manifest改为:
<application android:process="android.process.acore3" android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".FirstAppActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME_FIRST" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY" />
</intent-filter>
</activity>
</application>

然后将编译好的apk放到/out/target/product/generic/system/app目录下。

5)将Android自带的Launcher删除掉,包括源代码(packages/apps/Launcher)和apk(/out/target/product/generic/system/app/Launcher.apk)。

6)
做完这些工作,就可以重新编译Android了,我们可以编译修改过的几个相关的包。
如果之前编译过了Android源码,可以用mmm命令来编译部分的改动。
这里需要这样编译:

$ . build/envsetup.sh
$ mmm frameworks/base
$ mmm frameworks/base/services/java
$ mmm frameworks/policies/base/mid
$ mmm frameworks/policies/base/phone

7)
编译完成后重新生成img文件。
$ make snod

8) 现在可以启动Android模拟器来看效果了。
首先设置环境变量:
$ export ANDROID_PRODUCT_OUT= ./out/target/product/generic
然后切换到
$ cd ./out/host/linux-x86/bin
运行
$ ./emulator

这样我们启动的模拟器里面用的image就是我们刚才编译好的自己定制的东西了。
从模拟器上可以看到启动的Launcher是我们自己的Launcher,不会出现默认的Launcher了,也不会出现选择界面。

9)我们再验证一下,如果用户装上了一个其他的Launcher(Home)会怎么样。
从网上找一个一般的Launcher或者自己写一个一般的Launcher装上去,重新启动,不会出现选择界面。
按HOME键也不会出来两个HOME来选择。


这样我们就牢牢控制了用户的桌面。
只有我们自己定制的HOME才能装上。 这对于定制Android设备的厂商很有用处。

分享到:
评论
1 楼 yzyspy 2012-08-21  
ActivityManagerService:startHomeActivityLocked()启动的launcher!

相关推荐

    AnderWeb-android_packages_apps_Launcher-4458ee4.zip

    描述中提到的"AnderWeb-android_packages_apps_Launcher-4458ee4.zip"与标题相同,暗示这可能是一个从AnderWeb(一个可能的第三方Android开发或资源分享平台)下载的定制版Android启动器应用的源代码或者二进制文件...

    android打开系统APK

    APK文件在系统中被安装后,会有一个对应的包名(Package Name),它是区分不同应用的唯一标识。因此,要打开一个系统APK,我们首先需要知道该APK的包名。 以下是一个简单的示例代码,展示如何通过Intent启动一个...

    android调用第三方程序,只需包名

    Intent是Android中的一个核心概念,它用于启动活动(Activity)、服务(Service)或广播接收器(BroadcastReceiver)。当我们要打开一个第三方应用时,只需要知道该应用的包名,就可以创建一个Intent并启动它。以下...

    通过应用包名启动第三方应用

    在Android系统中,通过应用包名启动第三方应用是一项常见的操作,尤其在开发过程中。这个小demo展示的就是如何利用已知的第三方应用包名来启动该应用。应用包名是每个Android应用的唯一标识,它在应用程序的...

    给Android的应用换个图标(桌面快捷图标)sShortcut

    在Android上,快捷方式是一种指向应用程序特定功能的接口,用户可以通过长按应用图标或通过启动器(Launcher)创建。在API 25及更高版本中,Android引入了动态快捷方式(Dynamic Shortcuts),允许开发者创建和管理...

    一键启动第三方app.rar

    在IT行业中,一键启动第三方应用是一项常见的需求,尤其是在自动化测试、设备管理或者用户便捷操作的场景下。"一键启动第三方app.rar"这个压缩包文件很可能包含了一个实现此功能的程序或者代码示例,用于帮助开发者...

    Android移动应用开发基础教程第2章.pptx

    - 启动另一个活动:通过Intent对象来启动新的活动,Intent是Android中用于组件间通信的重要工具。 - 结束活动:调用finish()方法可结束当前活动,将其从任务栈中移除。 2.3 在活动中使用Intent Intent是一种消息...

    Android操作系统汇总adb的常用指令

    第一种方式是通过拨号界面输入命令来查询IMEI号;第二种方式除了查询IMEI号外还可以进行网络切换以及快速查询其他硬件信息。 - **快速查询硬件信息** `*#*#4636#*#*` 输入这个代码可以打开一个内置的菜单,用于...

    获取第三方apk的包名启动类名icon.rar

    在Android开发中,获取第三方APK的包名、启动类名以及图标是常见的需求,尤其在应用管理和自动化测试等领域。这个名为"获取第三方apk的包名启动类名icon.rar"的压缩包文件提供了相关的代码资源,尽管可能并非所有...

    安卓Android源码——快捷图标的创建与移除.zip

    1. **Intent Intents**: 创建快捷图标的第一步是定义一个`Intent`,这个`Intent`用于启动快捷方式。通常,我们需要创建一个`Intent`来指定要启动的Activity和一些额外的数据。 ```java Intent shortcutIntent = new...

    Pixelful_Icon_Pack_Pro_v7.1.apk

    受第一个也是唯一一个图标包的深色版本,其灵感来自于新的Pixel设备样式,旨在转变设备的图形。 重要说明 •这是一个图标包,需要自定义启动器才能工作。Google Now Launcher,Pixel Launcher或工厂安装的任何...

    Pixelful_Icon_Pack_Pro_v7.3.apk

    受新Pixel启发而开发的第一个也是唯一的图标包的深色版本,用于变换设备的图形设备的样式。 重要说明 •这是一个图标包,需要自定义启动器才能工作。Google Now Launcher,Pixel Launcher或工厂安装的任何其他启动器...

    关于实现点击某个应用时弹出自己指定的应用

    - 创建Intent:首先,你需要创建一个Intent对象,设置其ACTION_MAIN和CATEGORY_LAUNCHER属性,这通常代表启动一个应用的主界面。 - 添加ComponentName:接着,使用ComponentName类来指定你想打开的应用的包名和...

    A83T Android快速移植指南

    - **Android层的配置修改**: 对Android系统中的触控事件处理逻辑进行调整。 #### 3.5 G-Sensor配置 - **打包配置文件修改**: 修改与加速度传感器相关的配置文件。 - **Android层配置修改**: 在系统层面对加速度...

    java获取apk包名、版本、权限、图标、启动图等信息

    在Android开发中,Java语言是主要的编程工具,而 APK 是 Android 应用程序的打包格式。本主题将深入探讨如何使用Java来获取APK文件的相关信息,包括包名、版本、权限、图标以及启动图等关键元数据。这些信息对于理解...

    android基本入门

    #### 一、创建第一个Android应用程序:Hello World ##### 1. 创建项目的步骤 在本教程中,我们将通过Eclipse IDE创建一个简单的Android应用程序,并实现显示“Hello World”的功能。 **步骤1:** 打开Eclipse,...

    安卓获取apk包名类名

    在AndroidManifest.xml中,这个类被指定在 `&lt;activity&gt;` 标签内,特别是带有 `android.intent.category.LAUNCHER` 和 `android.intent.action.MAIN` 属性的 `&lt;intent-filter&gt;` 下。 获取APK包名和主类名有多种方法...

    Android发送通知Notification

    下面我们将深入探讨如何在Android应用中创建并发送一个基本的通知。 首先,创建通知涉及以下步骤: 1. **获取`NotificationManager`实例**: 通过调用`getSystemService()`方法,并传入`Context.NOTIFICATION_...

    7.四大组件之Activity.pptx

    在这个例子中,`.MainActivity` 是 Activity 的全限定类名,`android.intent.action.MAIN` 表示这是应用的主入口,而 `android.intent.category.LAUNCHER` 表示它会在应用程序列表中显示。 **Activity 中控件的添加...

Global site tag (gtag.js) - Google Analytics