<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          如何實現(xiàn)一個 System Services?

          共 26295字,需瀏覽 53分鐘

           ·

          2021-04-08 21:43

          Android 系統(tǒng)開發(fā)做什么?》寫到 Android System Services 是專注于特定功能的模塊化組件,應(yīng)用框架 API 所提供的功能可與系統(tǒng)服務(wù)通信,以訪問底層硬件。Android System Services 是如何寫的?來以 DisplayManagerService 為例,具體來看看。

          System Service 是如何寫的?

          應(yīng)用調(diào)用

           DisplayManager dm = getSystemService(DisplayManager.class);
           dm.setTemporaryBrightness(0.0f);
           Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);

          看下 getSystemService 方法,在 Context 類里。

          Context#getSystemService

          public final @Nullable <T> getSystemService(@NonNull Class<T> serviceClass) {
              // Because subclasses may override getSystemService(String) we cannot
              // perform a lookup by class alone.  We must first map the class to its
              // service name then invoke the string-based method.
              String serviceName = getSystemServiceName(serviceClass);
              return serviceName != null ? (T)getSystemService(serviceName) : null;
          }

          public abstract @Nullable String getSystemServiceName(@NonNull Class<?> serviceClass);

          ContextImpl#getSystemService

          @Override
          public String getSystemServiceName(Class<?> serviceClass) {
              return SystemServiceRegistry.getSystemServiceName(serviceClass);
          }

          繼續(xù)跟 SystemServiceRegistry.getSystemServiceName。

          SystemServiceRegistry#getSystemServiceName

          public static String getSystemServiceName(Class<?> serviceClass) {
              if (serviceClass == null) {
                  return null;
              }
              final String serviceName = SYSTEM_SERVICE_NAMES.get(serviceClass);
              if (sEnableServiceNotFoundWtf && serviceName == null) {
                  // This should be a caller bug.
                  Slog.wtf(TAG, "Unknown manager requested: " + serviceClass.getCanonicalName());
              }
              return serviceName;
          }

          什么時候 registerService 的?

          public final class SystemServiceRegistry {
              static {
                  registerService(Context.DISPLAY_SERVICE, DisplayManager.class,
                  new CachedServiceFetcher<DisplayManager>() 
          {
                      @Override
                      public DisplayManager createService(ContextImpl ctx) {
                          return new DisplayManager(ctx.getOuterContext());
                      }
                  });
              }
          }
          private static <T> void registerService(@NonNull String serviceName,
                  @NonNull Class<T> serviceClass, @NonNull ServiceFetcher<T> serviceFetcher)
           
          {
              SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
              SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
              SYSTEM_SERVICE_CLASS_NAMES.put(serviceName, serviceClass.getSimpleName());
          }

          結(jié)合上面的分析代碼可以知道 getSystemService(DisplayManager.class)得到的是一個 DisplayManager 的實例。

          接下來看 dm.setTemporaryBrightness 方法。

          DisplayManager#setTemporaryBrightness

          public void setTemporaryBrightness(float brightness) {
              mGlobal.setTemporaryBrightness(brightness);
          }

          mGlobal 是 DisplayManagerGlobal 對象。

          DisplayManagerGlobal#setTemporaryBrightness

          private final IDisplayManager mDm;

          private DisplayManagerGlobal(IDisplayManager dm) {
              mDm = dm;
          }

          public static DisplayManagerGlobal getInstance() {
              synchronized (DisplayManagerGlobal.class{
                  if (sInstance == null) {
                      IBinder b = ServiceManager.getService(Context.DISPLAY_SERVICE);
                      if (b != null) {
                          sInstance = new DisplayManagerGlobal(IDisplayManager.Stub.asInterface(b));
                      }
                  }
                  return sInstance;
              }
          }
          public void setTemporaryBrightness(float brightness) {
              try {
                  mDm.setTemporaryBrightness(brightness);
              } catch (RemoteException ex) {
                  throw ex.rethrowFromSystemServer();
              }
          }

          mDm 是 IDisplayManager 對象,初始化在IDisplayManager.Stub.asInterface(ServiceManager.getService(Context.DISPLAY_SERVICE)),看到 IDisplayManager 是一個 aidl 文件:frameworks/base/core/java/android/hardware/display/IDisplayManager.aidl,AIDL (Android Interface Definition Language) 是 Android 中的接口定義文件,為系統(tǒng)提供了一種簡單跨進程通信方法,先不管 AIDL。

          IDisplayManager

          IDisplayManager 定義了包括 setTemporaryBrightness 的幾個接口。

          interface IDisplayManager {
              //……
              void registerCallback(in IDisplayManagerCallback callback);

              // Requires CONFIGURE_WIFI_DISPLAY permission.
              // The process must have previously registered a callback.
              void startWifiDisplayScan();

              // Requires CONFIGURE_WIFI_DISPLAY permission.
              void stopWifiDisplayScan();

              // Requires CONFIGURE_WIFI_DISPLAY permission.
              void connectWifiDisplay(String address);

              // No permissions required.
              void disconnectWifiDisplay();

              // Temporarily sets the display brightness.
              void setTemporaryBrightness(float brightness);
              //……
          }

          IDisplayManager 只是接口,需要找下哪里實現(xiàn)了它,搜索是在 BinderService,BinderService 是 DisplayManagerService 內(nèi)部類。

          final class BinderService extends IDisplayManager.Stub {
              @Override // Binder call
              public void setTemporaryBrightness(float brightness) {
                  mContext.enforceCallingOrSelfPermission(
                          Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
                          "Permission required to set the display's brightness");
                  final long token = Binder.clearCallingIdentity();
                  try {
                      synchronized (mSyncRoot) {
                          mDisplayPowerController.setTemporaryBrightness(brightness);
                      }
                  } finally {
                      Binder.restoreCallingIdentity(token);
                  }
              }
          }

          mDisplayPowerController.setTemporaryBrightness(brightness)后面經(jīng)過一系列調(diào)用會到 LightsService#setLight_native,通過 JNI 調(diào)用到 native 層,調(diào)用底層進行背光調(diào)節(jié),關(guān)于背光調(diào)節(jié)后面文章再細講。

          SystemServer

          DisplayManagerService 是繼承了 SystemService,DisplayManagerService 是怎么注冊為系統(tǒng)服務(wù)的呢?在 SystemServer 里面:

          private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
              t.traceBegin("StartDisplayManager");
              //開啟DisplayManagerService
              mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
              t.traceEnd();
          }
          private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
              //通知服務(wù)系統(tǒng)啟動完成
              t.traceBegin("MakeDisplayManagerServiceReady");
              try {
                  // TODO: use boot phase and communicate these flags some other way
                  mDisplayManagerService.systemReady(safeMode, mOnlyCore);
              } catch (Throwable e) {
                  reportWtf("making Display Manager Service ready", e);
              }
              t.traceEnd();
          }

          看完 DisplayManagerService 是怎么寫的,不妨模仿寫個。所謂看著代碼,感覺還是挺簡單的,實際操作起來,各種編譯報錯……

          如何寫個 System Service

          先上圖:

          1.編寫 AIDL 文件

          新建 frameworks/base/core/java/android/hardware/wuxiaolong/IWuXiaolongManager.aidl,內(nèi)容如下:

          package android.hardware.wuxiaolong;
          /** @hide */
          interface IWuXiaolongManager {

              String getName();
          }

          2.Context 定義變量

          在 Context 里定義一個代表 wuxiaolong 服務(wù)的字符串 frameworks/base/core/java/android/content/Context.java

          public static final String WUXIAOLONG_SERVICE = "wuxiaolong";

          3.編寫系統(tǒng)服務(wù)

          frameworks/base/services/core/java/com/android/server/wuxiaolong/WuXiaolongManagerService.java

          package com.android.server.wuxiaolong;

          import android.content.Context;
          import android.hardware.wuxiaolong.IWuXiaolongManager;

          public class WuXiaolongManagerService extends IWuXiaolongManager.Stub {
              private final Context mContext;

              public WuXiaolongManagerService(Context context) {
                  super();
                  mContext = context;
              }

              @Override
              public String getName() {
                  String name = "WuXiaolong..";
                  return name;
              }
          }

          4.注冊系統(tǒng)服務(wù)

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

          import com.android.server.wuxiaolong.WuXiaolongManagerService;
          private void startOtherServices() {
              // 部分代碼省略...
              try {
                  android.util.Log.d("wxl","SystemServer WuXiaolongManagerService");
                  ServiceManager.addService(Context.WUXIAOLONG_SERVICE, new WuXiaolongManagerService(context));
              } catch (Throwable e) {
                  reportWtf("starting WuXiaolongManagerService", e);
              }
              // 部分代碼省略...
          }

          5.編寫 Manager 類

          frameworks/base/core/java/android/hardware/wuxiaolong/WuXiaolongManager.java


          package android.hardware.wuxiaolong;

          import android.os.IBinder;
          import android.os.ServiceManager;
          import android.hardware.wuxiaolong.IWuXiaolongManager;
          import android.content.Context;
          import android.os.RemoteException;
          import android.compat.annotation.UnsupportedAppUsage;
          import android.annotation.Nullable;
          import android.os.ServiceManager.ServiceNotFoundException;
          import android.annotation.SystemService;

          @SystemService(Context.WUXIAOLONG_SERVICE)
          public class WuXiaolongManager {
              private static WuXiaolongManager sInstance;
              private final IWuXiaolongManager mService;
              private Context mContext;

              /**
               * @hide
               */

              public WuXiaolongManager(IWuXiaolongManager iWuXiaolongManager) {
                  mService = iWuXiaolongManager;
              }

              /**
               * Gets an instance of the WuXiaolong manager.
               *
               * @return The WuXiaolong manager instance.
               * @hide
               */

              @UnsupportedAppUsage
              public static WuXiaolongManager getInstance() {
                  android.util.Log.d("wxl""WuXiaolongManager getInstance");
                  synchronized (WuXiaolongManager.class{
                      if (sInstance == null) {

                          try {
                              IBinder b = ServiceManager.getServiceOrThrow(Context.WUXIAOLONG_SERVICE);
                              sInstance = new WuXiaolongManager(IWuXiaolongManager.Stub
                                      .asInterface(ServiceManager.getServiceOrThrow(Context.WUXIAOLONG_SERVICE)));
                          } catch (ServiceNotFoundException e) {
                              throw new IllegalStateException(e);
                          }

                      }
                      return sInstance;
                  }
              }

              @Nullable
              public String getName() {
                  android.util.Log.d("wxl""WuXiaolongManager getName");
                  try {
                      return mService.getName();
                  } catch (RemoteException e) {
                      throw e.rethrowFromSystemServer();
                  }
              }
          }

          6.注冊 Manager

          frameworks/base/core/java/android/app/SystemServiceRegistry.java

          import android.hardware.wuxiaolong.WuXiaolongManager;
          static {
              registerService(Context.WUXIAOLONG_SERVICE, WuXiaolongManager.class,
                      new CachedServiceFetcher<WuXiaolongManager>() 
          {
                          @Override
                          public WuXiaolongManager createService(ContextImpl ctx)
                                  throws ServiceNotFoundException 
          {
                              android.util.Log.d("wxl","SystemServiceRegistry registerService");
                              return WuXiaolongManager.getInstance();
                          }});
          }

          7.應(yīng)用調(diào)用

          WuXiaolongManager mWuXiaolongManager = (WuXiaolongManager)mContext.getSystemService(Context.WUXIAOLONG_SERVICE);
          android.util.Log.d("wxl","Name="+ mWuXiaolongManager.getName());

          8.解決報錯

          編譯報錯

          • 報錯 1:
          ******************************
          You have tried to change the API from what has been previously approved.

          To make these errors go away, you have two choices:
             1. You can add '@hide' javadoc comments (and remove @SystemApi/@TestApi/etc)
                to the new methods, etc. shown in the above diff.

             2. You can update current.txt and/or removed.txt by executing the following command:
                   make api-stubs-docs-non-updatable-update-current-api

                To submit the revised current.txt to the main Android repository,
                you will need approval.
          ******************************

          需要執(zhí)行 make update-api,更新接口,會多出來:

          frameworks/base/api/current.txt

          diff --git a/api/current.txt b/api/current.txt
          index 6b1a96c..0779378 100755
          --- a/api/current.txt
          +++ b/api/current.txt
          @@ -10256,6 +10256,7 @@ package android.content {
               field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
               field public static final String WIFI_SERVICE = "wifi";
               field public static final String WINDOW_SERVICE = "window";
          +    field public static final String WUXIAOLONG_SERVICE = "wuxiaolong";
             }

             public class ContextWrapper extends android.content.Context {
          @@ -18318,6 +18319,14 @@ package android.hardware.usb {

           }

          +package android.hardware.wuxiaolong {
          +
          +  public class WuXiaolongManager {
          +    method @Nullable public String getName();
          +  }
          +
          +}
          +
           package android.icu.lang {

          frameworks/base/non-updatable-api/current.txt

          diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
          index adf1bb5..e738c02 100755
          --- a/non-updatable-api/current.txt
          +++ b/non-updatable-api/current.txt
          @@ -10256,6 +10256,7 @@ package android.content {
               field public static final String WIFI_RTT_RANGING_SERVICE = "wifirtt";
               field public static final String WIFI_SERVICE = "wifi";
               field public static final String WINDOW_SERVICE = "window";
          +    field public static final String WUXIAOLONG_SERVICE = "wuxiaolong";
             }

             public class ContextWrapper extends android.content.Context {
          @@ -18318,6 +18319,14 @@ package android.hardware.usb {

           }

          +package android.hardware.wuxiaolong {
          +
          +  public class WuXiaolongManager {
          +    method @Nullable public String getName();
          +  }
          +
          +}
          +
           package android.icu.lang {
          • 報錯 2:
          [0mManagers must always be obtained from Context; no direct constructors [ManagerConstructor]

          編寫 Manager 類需寫成單例。

          • 報錯 3:
          Missing nullability on method `getName` return [MissingNullability]

          getName 方法加上@Nullable注解。

          運行報錯

          04-08 15:41:38.798   297   297 E SELinux : avc:  denied  { find } for pid=12717 uid=1000 name=wuxiaolong scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_service:s0 tclass=service_manager permissive=1
          04-08 15:41:38.802 12717 12758 E AndroidRuntime: *** FATAL EXCEPTION IN SYSTEM PROCESS: PowerManagerService
          04-08 15:41:38.802 12717 12758 E AndroidRuntime: java.lang.IllegalStateException: android.os.ServiceManager$ServiceNotFoundException: No service published for: wuxiaolong
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.hardware.wuxiaolong.WuXiaolongManager.getInstance(WuXiaolongManager.java:47)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.app.SystemServiceRegistry$27.createService(SystemServiceRegistry.java:497)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.app.SystemServiceRegistry$27.createService(SystemServiceRegistry.java:493)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.app.SystemServiceRegistry$CachedServiceFetcher.getService(SystemServiceRegistry.java:1760)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.app.SystemServiceRegistry.getSystemService(SystemServiceRegistry.java:1440)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.app.ContextImpl.getSystemService(ContextImpl.java:1921)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at com.android.server.display.DisplayPowerController.updatePowerState(DisplayPowerController.java:1191)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at com.android.server.display.DisplayPowerController.access$700(DisplayPowerController.java:92)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at com.android.server.display.DisplayPowerController$DisplayControllerHandler.handleMessage(DisplayPowerController.java:2074)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.os.Handler.dispatchMessage(Handler.java:106)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.os.Looper.loop(Looper.java:223)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.os.HandlerThread.run(HandlerThread.java:67)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at com.android.server.ServiceThread.run(ServiceThread.java:44)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime: Caused by: android.os.ServiceManager$ServiceNotFoundException: No service published for: wuxiaolong
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.os.ServiceManager.getServiceOrThrow(ServiceManager.java:153)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  at android.hardware.wuxiaolong.WuXiaolongManager.getInstance(WuXiaolongManager.java:40)
          04-08 15:41:38.802 12717 12758 E AndroidRuntime:  ... 12 more

          這里是缺少 SELinux 權(quán)限,可執(zhí)行:

          adb shell
          setenforce 0 (臨時禁用掉SELinux)
          getenforce  (得到結(jié)果為Permissive)

          臨時禁用掉 SELinux,功能就正常了,關(guān)于 SELinux 這里不說了,后面有機會寫篇 SELinux 文章。

          最后 Log 打印如下:

          Line 83204-08 16:08:55.290 17649 17690 D wxl     : SystemServiceRegistry registerService
          Line 83304-08 16:08:55.290 17649 17690 D wxl     : WuXiaolongManager getInstance
          Line 83504-08 16:08:55.292 17649 17690 D wxl     : WuXiaolongManager getName
          Line 83604-08 16:08:55.293 17649 17690 D wxl     : Name=WuXiaolong..

          手寫個 System Service 實踐過后沒那么簡單,光 SELinux 權(quán)限夠折騰半天了,這篇文章先就醬紫吧。

          瀏覽 70
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产性爱第一页 | 久久无码专区 | 国产成人在线免费观看视频 | 永久在线国产 | 在线观看国产一级片 |