[android]componentname

Posted by Kev.L Blog on September 20, 2019

壁纸不显示问题总结

  • 通过日志分析 W/WallpaperManager(pid):WallpaperService not running初步定位是服务没有开启的原因

  • /system/build.prop 中增加 sys.wallpaper.enable=true 之后继续追查 log

    • 首先开机之后查看服务状态是正确的

      1
      2
      
      root@p201_iptv:/ # getprop | grep wallpaper
      [sys.wallpaper.enable]: [true]
      
    • 发现log中还是会打印W/WallpaperManager(pid):WallpaperService not running


  • 然后代码追定位到 frameworks/base/services/java/com/android/server/SystemServer.java

    honestly speaking , I don’t know why direct here , but chaoyang bro let me do that.

    • 搜索 Wallpaper 找到系统服务添加wallpaper的代码

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      
      if (!disableNonCoreServices && context.getResources().getBoolean(
                              R.bool.config_enableWallpaperService) &&
                              SystemProperties.getBoolean("sys.wallpaper.enable", false)) {
                      try {
                          Slog.i(TAG, "Wallpaper Service");
                          if (!headless) {               
                              wallpaper = new WallpaperManagerService(context);
                              ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
                          }         
                      } catch (Throwable e) {        
                          reportWtf("starting Wallpaper Service", e);
                      }
                  }
           
      

      继续查找,initAndLoop() 方法里,创建了一个对象 wallpaperF

      1
      
      final WallpaperManagerService wallpaperF = wallpaper;
      

      这里会检测这个标志位,如果不为1,就创建一个 systemUi 线程

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      
                      Thread th = new Thread("test") {
                          public void run() {
                              try {
                                  Thread.sleep(3000);
                              } catch (Exception e) {}
                              if (!headless) {
                                  startSystemUi(contextF);
                              }
                          }
                      };
                      if (SystemProperties.getBoolean("sys.wallpaper.enable", false))
                          th.start();
           
      

      wallpaperF.systemRunning()

      1
      2
      3
      4
      5
      6
      7
      8
      
           
                      try {
                          if (wallpaperF != null) wallpaperF.systemRunning();
                      } catch (Throwable e) {        
                          reportWtf("Notifying WallpaperService running", e);
                      }
                      Slog.i(TAG, "BootStage Notifying WallpaperService running");
           
      

      继续追到 WallpaperManagerService.java

      可以看到 ComponentName 这里 调用了包名 com.android.systemui ,百度一下这个包名对应的 apk 是 SystemUI.apk ,使用 pm install 安装这个apk , 背景图片显示正常

      1
      2
      3
      4
      5
      6
      
          /**  
           * Name of the component used to display bitmap wallpapers from either the gallery or
           * built-in wallpapers.
           */
          static final ComponentName IMAGE_WALLPAPER = new ComponentName("com.android.systemui",
                  "com.android.systemui.ImageWallpaper");
      

      这里简单介绍一下 ComponentName 的使用

      ComponentName:可以启动其他应用的Activity、Service.

      1
      2
      3
      4
      5
      
      ComponentName    chatActivity =new ComponentName(param1,param2);
           
      param1:Activity、Service所在应用的包名
           
      param2:Activity、Service的包名+类名
      

      Activity:

      1
      2
      3
      4
      5
      6
      7
      
       ComponentName chatActivity =new ComponentName("com.npf.chat", "com.npf.chat.ui.ChatActivity");
           
          Intent intent =new Intent();
           
          intent.setComponent(chatActivity);
           
          startActivity(intent);
      

      Service:

      1
      2
      3
      4
      5
      6
      7
      
        ComponentName chatService =new ComponentName("com.npf.chat", "com.npf.chat.ui.ChatService");
           
          Intent intent =new Intent();
           
          intent.setComponent(chatService );
           
          startService(intent);
      

      注:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      
      如果该Activity非应用入口(入口Activity默认android:exported="true"),则需要再清单文件中添加   android:exported="true"。Service也需要添加android:exported="true"。允许外部应用调用。
           
         <activity android:name="com.npf.chat.ui.ChatActivity"
           
          android:exported="true"/>
           
         <service android:name="com.npf.chat.ui.ChatService"
           
          android:exported="true"/>
      

ComponenetName : 组件名称

Java中可以通过Intent.setComponent(ComponentName) 来启动其他应用(项目)的Activity 或者Service 。

创建ComponentName对象需要两个参数:

package name (String): 这里的包名为String格式,一般与Manifest中的package 值相同。

1
2
3
4
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test"
    android:versionCode="1"
    android:versionName="1.0" >

acitivity name (String): 第二个参数为目标Activity/Service 全称(包名+类名),String 格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    String packageName = "com.example.test";
    String activityName = "com.example.test.MyActivity";
    String serviceName = "com.example.test.MyService";

    //启动Activity
    Intent intentActivity = new Intent();
    ComponentName componentNameActivity = new ComponentName(packageName ,activityName);
    intentActivity.setComponent(componentNameActivity);
    startActivity(intentActivity);

    //启动Service
    Intent intentService = new Intent();
    ComponentName componentNameService = new ComponentName(packageName ,serviceName);
    intentService.setComponent(componentNameService);
    startActivity(intentService);

Tips: 如果请求的Activity 是其他应用的入口Activity,即在Manifest中:

1
2
3
4
5
<intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>

则此时默认 android:exported=”true”,无需设置也可以成功调用。若不是,则需要手动添加android:exported=”true”。