SystemServer 启动新增服务APK

简介: SystemServer 启动新增服务APK

平台:


RK3288 + android 7.1


问题:


无法在动画过程启动新增加服务.


LOG输出:


01-01 20:00:18.053 686-713/system_process W/ActivityManager: Unable to start


service Intent { act=action pkg=pkgName }


U=0: not found


分析:


|-- frameworks/base/services/java/com/android/server/SystemServer.java


/**
     * Starts some essential services that are not tangled up in the bootstrap process.
     */
    private void startCoreServices() {
        // Tracks the battery level.  Requires LightService.
        mSystemServiceManager.startService(BatteryService.class);
        // Tracks application usage stats.
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
        // Tracks whether the updatable WebView is in a ready state and watches for update installs.
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
  try{
    //Anson MyService Service
    mSystemServiceManager.startService(MyService.class);
  }catch (Throwable e) {
           reportWtf("starting MyService", e);
  }
    }


新增MyService.java:


|-- frameworks/base/services/core/java/com/android/server/os/MyService.java


public final class MyService extends SystemService implements Handler.Callback {
    private static final String TAG = "MyService";
  private final Context mContext;
  private ServiceThread mHandlerThread;
  private Handler mHandler;
  private Intent serviceIntent = null;
  public MyService(Context context) {
  super(context);
  mContext = context;
  mHandlerThread = new ServiceThread(TAG, android.os.Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
        mHandlerThread.start();
        mHandler = new Handler(mHandlerThread.getLooper(), this);
  }
  @Override
    public boolean handleMessage(android.os.Message msg) {
        switch(msg.what) {
  }
  return true;
  }
  @Override
  public void onStart(){
  Log.d(TAG, "ALog onStart");
  }
  @Override
    public void onBootPhase(int phase) {
        //在AM 初始化完成后执行.
        if (phase == PHASE_ACTIVITY_MANAGER_READY) {
    mHandler.postDelayed(checkService, INTERVAL);
            connectToService();
        }
    }
  final int INTERVAL = 1000;
  private Runnable checkService = new Runnable(){
  public void run(){
    if(!isServiceReady()){
    mHandler.postDelayed(this, INTERVAL);
    connectToService();
    }
  }
  };
  private void connectToService(){
  Log.d(TAG, "ALog connectToService()");
  try{
    if(serviceIntent == null){
    final Intent bindIntent = new Intent(action);
    bindIntent.setComponent(new ComponentName(pkgName, className));
    serviceIntent = bindIntent;
    }
    int flags = Context.BIND_IMPORTANT | Context.BIND_FOREGROUND_SERVICE
      | Context.BIND_AUTO_CREATE;
            //由这里启动服务
    mContext.bindServiceAsUser(serviceIntent, bindConn, flags, android.os.UserHandle.SYSTEM);
  }catch(Exception e){
    e.printStackTrace();
  }
  }
  //ISystemControler mBinder;
  final ServiceConnection bindConn = new ServiceConnection(){
  public void onServiceConnected(ComponentName name, android.os.IBinder service){
    Log.d(TAG, "ALog onServiceConnected");
    mHandler.removeCallbacks(checkService);
    //mBinder = ISystemControler.Stub.asInterface(service);
    publishBinderService(Context.SYSTEMCTRL_SERVICE, service);
  }
  public void onServiceDisconnected(ComponentName name){
    Log.d(TAG, "ALog onServiceDisconnected");
    //mBinder = null;
  }
  };
  private boolean isServiceReady(){
  return null != android.os.ServiceManager.checkService(Context.SYSTEMCTRL_SERVICE);
  }
}
|-- frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
private ServiceLookupResult retrieveServiceLocked(Intent service,
            String resolvedType, String callingPackage, int callingPid, int callingUid, int userId,
            boolean createIfNeeded, boolean callingFromFg, boolean isBindExternal) {
        ServiceRecord r = null;
        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "retrieveServiceLocked: " + service
                + " type=" + resolvedType + " callingUid=" + callingUid);
        userId = mAm.mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
                ActivityManagerService.ALLOW_NON_FULL_IN_PROFILE, "service", null);
        ServiceMap smap = getServiceMap(userId);
        final ComponentName comp = service.getComponent();
        if (comp != null) {
            r = smap.mServicesByName.get(comp);
        }
        if (r == null && !isBindExternal) {
            Intent.FilterComparison filter = new Intent.FilterComparison(service);
            r = smap.mServicesByIntent.get(filter);
        }
        if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0
                && !callingPackage.equals(r.packageName)) {
            // If an external service is running within its own package, other packages
            // should not bind to that instance.
            r = null;
        }
        if (r == null) {
            try {
                // TODO: come back and remove this assumption to triage all services
                ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service,
                        resolvedType, ActivityManagerService.STOCK_PM_FLAGS
                                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                        userId);
                ServiceInfo sInfo =
                    rInfo != null ? rInfo.serviceInfo : null;
                if (sInfo == null) {
                    Slog.w(TAG_SERVICE, "Unable to start service " + service + " U=" + userId +
                          ": not found");
                    return null;
                }


问题跟踪:


在MyService.java中加入了服务启动检测, 若不存在, 则在1s 后尝试启动.


在测试过程中发现, 需尝试3次以上才能正常启动.


01-01 20:00:13.042 686-700/system_process D/PackageManager: ALog resolveService Intent { act=action cmp=serviceClass }

   ALog queryIntentServicesInternal by comp(ComponentInfo{pkg/cls})


   ALog getServiceInfo s != null mSettings.isEnabledAndMatchLPr(s.info, flags, userId) = false.


最终LOG定位到 isEnabledAndMatchLPr 函数执行的返回值, 相关代码如下:


//frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
    @Override
    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;
  d("resolveService " + intent.toString());
        flags = updateFlagsForResolve(flags, userId, intent);
        List<ResolveInfo> query = queryIntentServicesInternal(intent, resolvedType, flags, userId);
        if (query != null) {
            if (query.size() >= 1) {
                // If there is more than one service with the same priority,
                // just arbitrarily pick the first one.
                return query.get(0);
            }
        }
  d("resolveService could NOT found");
        return null;
    }
private @NonNull List<ResolveInfo> queryIntentServicesInternal(Intent intent,
            String resolvedType, int flags, int userId) {
        ...
        if (comp != null) {
    d("queryIntentServicesInternal by comp(" + comp.toString() + ")");
            final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1);
            final ServiceInfo si = getServiceInfo(comp, flags, userId);
            if (si != null) {
                final ResolveInfo ri = new ResolveInfo();
                ri.serviceInfo = si;
                list.add(ri);
            }
            return list;
        }
        ..
    }
    @Override
    public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
        ...
        synchronized (mPackages) {
            PackageParser.Service s = mServices.mServices.get(component);
            if (DEBUG_PACKAGE_INFO) Log.v(
                TAG, "getServiceInfo " + component + ": " + s);
    d("getServiceInfo flags = " + flags);
    if(s == null){
    d("getServiceInfo s == null");
    }else{
    d("getServiceInfo s != null mSettings.isEnabledAndMatchLPr(s.info, flags, userId) = " + (mSettings.isEnabledAndMatchLPr(s.info, flags, userId)));
    }
            if (s != null && mSettings.isEnabledAndMatchLPr(s.info, flags, userId)) {
                PackageSetting ps = mSettings.mPackages.get(component.getPackageName());
                if (ps == null) return null;
                return PackageParser.generateServiceInfo(s, flags, ps.readUserState(userId),
                        userId);
            }
        }
        return null;
    }
//frameworks/base/services/core/java/com/android/server/pm/Settings.java
    boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
        final PackageSetting ps = mPackages.get(componentInfo.packageName);
        if (ps == null) return false;
        final PackageUserState userState = ps.readUserState(userId);
        return userState.isMatch(componentInfo, flags);
    }
//frameworks/base/core/java/android/content/pm/PackageUserState.java
    /**
     * Test if the given component is considered installed, enabled and a match
     * for the given flags.
     *
     * <p>
     * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
     * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
     * </p>
     */
    public boolean isMatch(ComponentInfo componentInfo, int flags) {
        if (!isInstalled(flags)) return false;
        if (!isEnabled(componentInfo, flags)) return false;
        if ((flags & MATCH_SYSTEM_ONLY) != 0) {
            if (!componentInfo.applicationInfo.isSystemApp()) {
                return false;
            }
        }
        final boolean matchesUnaware = ((flags & MATCH_DIRECT_BOOT_UNAWARE) != 0)
                && !componentInfo.directBootAware;
        final boolean matchesAware = ((flags & MATCH_DIRECT_BOOT_AWARE) != 0)
                && componentInfo.directBootAware;
        return matchesUnaware || matchesAware;
    }


到这里, 意识到跟 flags有点关系, 于是, 打印出了flags的值:


失败:  


ALog getServiceInfo flags = 268960768


成功:


   ALog getServiceInfo flags = 269222912


有什么区别?


268960768 -> #10080400


269222912 -> #100C0400


两个数的16进制相减为 #40000, 这个FLAG的定义如下:


|--frameworks/base/core/java/android/content/pm/PackageManager.java


/**
     * Querying flag: match components which are direct boot <em>unaware</em> in
     * the returned info, regardless of the current user state.
     * <p>
     * When neither {@link #MATCH_DIRECT_BOOT_AWARE} nor
     * {@link #MATCH_DIRECT_BOOT_UNAWARE} are specified, the default behavior is
     * to match only runnable components based on the user state. For example,
     * when a user is started but credentials have not been presented yet, the
     * user is running "locked" and only {@link #MATCH_DIRECT_BOOT_AWARE}
     * components are returned. Once the user credentials have been presented,
     * the user is running "unlocked" and both {@link #MATCH_DIRECT_BOOT_AWARE}
     * and {@link #MATCH_DIRECT_BOOT_UNAWARE} components are returned.
     *
     * @see UserManager#isUserUnlocked()
     */
    public static final int MATCH_DIRECT_BOOT_UNAWARE = 0x00040000;


解决:


在新增加服务APK的AndroidManifest.xml中加入        


android:directBootAware="true"

如:


...
<application
        android:label="@string/app_label"
  android:icon="@mipmap/ic_launcher"
        android:process="system"
  android:directBootAware="true"
        android:supportsRtl="true">
...


相关文章
WXM
|
Java 应用服务中间件 Maven
|
9月前
|
Java 中间件 调度
SpringBoot整合XXL-JOB【03】- 执行器的使用
本文介绍了如何将调度中心与项目结合,通过配置“执行器”实现定时任务控制。首先新建SpringBoot项目并引入依赖,接着配置xxl-job相关参数,如调度中心地址、执行器名称等。然后通过Java代码将执行器注册为Spring Bean,并声明测试方法使用`@XxlJob`注解。最后,在调度中心配置并启动定时任务,验证任务是否按预期执行。通过这些步骤,读者可以掌握Xxl-Job的基本使用,专注于业务逻辑的编写而无需关心定时器本身的实现。
1695 10
SpringBoot整合XXL-JOB【03】-  执行器的使用
|
Web App开发 测试技术 API
Python Playwright 基本使用(步骤详细)
Python Playwright 基本使用(步骤详细)
2614 0
|
SQL 关系型数据库 数据建模
Dify数据库结构导出到PowerDesigner
Dify是开源大语言模型应用开发平台,助力快速构建生成式AI应用。PowerDesigner是SAP的企业级建模工具,用于数据建模、业务流程建模和企业架构规划。通过PostgreSQL的`pg_dump`导出表结构到SQL文件,然后在PowerDesigner中导入生成物理数据模型,从而实现Dify数据库结构到PowerDesigner的迁移。
721 1
|
Java 数据库连接 Maven
IDEA创建SpringBoot的多模块项目教程
IDEA创建SpringBoot的多模块项目教程
791 0
|
大数据 Linux Android开发
Android ParcelFileDescriptor实现进程间通信
Android ParcelFileDescriptor实现进程间通信
414 0
|
存储 安全 Java
Java 移除List中的元素,这玩意讲究!
Java 移除List中的元素,这玩意讲究!
951 0
Java 移除List中的元素,这玩意讲究!
File类详解(获取文件名称、大小、路径、创建等)
File类详解(获取文件名称、大小、路径、创建等)
1432 1
|
XML 测试技术 API
JMeter和Postman:哪一个更适合性能测试?
Postman 和 JMeter 都可以用来做 API 测试,但是它们之间有一些区别。
|
SQL 关系型数据库 MySQL
Linux安装Zookeeper详细步骤(下载,安装,配置,启动,停止)
Linux安装Zookeeper详细步骤(下载,安装,配置,启动,停止)
5509 0