您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關怎么實現System Services的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
DisplayManager dm = getSystemService(DisplayManager.class); dm.setTemporaryBrightness(0.0f); Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);
看下 getSystemService 方法,在 Context 類里。
public final @Nullable <T> 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);
@Override public String getSystemServiceName(Class<?> serviceClass) { return SystemServiceRegistry.getSystemServiceName(serviceClass); }
繼續跟 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()); }
結合上面的分析代碼可以知道 getSystemService(DisplayManager.class)得到的是一個 DisplayManager 的實例。
接下來看 dm.setTemporaryBrightness 方法。
public void setTemporaryBrightness(float brightness) { mGlobal.setTemporaryBrightness(brightness); }
mGlobal 是 DisplayManagerGlobal 對象。
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 中的接口定義文件,為系統提供了一種簡單跨進程通信方法,先不管 AIDL。
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 只是接口,需要找下哪里實現了它,搜索是在 BinderService,BinderService 是 DisplayManagerService 內部類。
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)
后面經過一系列調用會到 LightsService#setLight_native,通過 JNI 調用到 native 層,調用底層進行背光調節,關于背光調節后面文章再細講。
DisplayManagerService 是繼承了 SystemService,DisplayManagerService 是怎么注冊為系統服務的呢?在 SystemServer 里面:
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) { t.traceBegin("StartDisplayManager"); //開啟DisplayManagerService mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class); t.traceEnd(); } private void startOtherServices(@NonNull TimingsTraceAndSlog t) { //通知服務系統啟動完成 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 是怎么寫的,不妨模仿寫個。 所謂看著代碼,感覺還是挺簡單的,實際操作起來,各種編譯報錯……
先上圖:
新建 frameworks/base/core/java/android/hardware/wuxiaolong/IWuXiaolongManager.aidl,內容如下:
package android.hardware.wuxiaolong; /** @hide */ interface IWuXiaolongManager { String getName(); }
在 Context 里定義一個代表 wuxiaolong 服務的字符串 frameworks/base/core/java/android/content/Context.java
public static final String WUXIAOLONG_SERVICE = "wuxiaolong";
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; } }
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); } // 部分代碼省略... }
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(); } } }
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(); }}); }
WuXiaolongManager mWuXiaolongManager = (WuXiaolongManager)mContext.getSystemService(Context.WUXIAOLONG_SERVICE); android.util.Log.d("wxl","Name="+ mWuXiaolongManager.getName());
報錯 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. ******************************
需要執行 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 權限,可執行:
adb shell setenforce 0 (臨時禁用掉SELinux) getenforce (得到結果為Permissive)
臨時禁用掉 SELinux,功能就正常了,關于 SELinux 這里不說了,后面有機會寫篇 SELinux 文章。
最后 Log 打印如下:
Line 832: 04-08 16:08:55.290 17649 17690 D wxl : SystemServiceRegistry registerService Line 833: 04-08 16:08:55.290 17649 17690 D wxl : WuXiaolongManager getInstance Line 835: 04-08 16:08:55.292 17649 17690 D wxl : WuXiaolongManager getName Line 836: 04-08 16:08:55.293 17649 17690 D wxl : Name=WuXiaolong..
感謝各位的閱讀!關于“怎么實現System Services”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。