Android系统开发 在Android10版本的Framework中添加系统服务
<h1><span style="color: rgba(22, 145, 121, 1)">版权声明</span></h1><p>本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17872077.html</p>
<div>本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。</div>
<h1><span style="color: rgba(22, 145, 121, 1)">前言</span></h1>
<p><span style="color: rgba(22, 145, 121, 1)"> <span style="color: rgba(0, 0, 0, 1)"> 此博客讲解如何在Android10版本的framework中添加系统服务。 在framework中添加我们自己的定制服务在系统开发中特别有意义。</span></span></p>
<p><span style="color: rgba(22, 145, 121, 1)"><span style="color: rgba(0, 0, 0, 1)"> 大多数的设备开发场景,都会开发一个应用启动一个后台服务,预装到系统中,让他获得系统级权限,调用大多数的系统级服务以提供外包应用调用系统级功能。 但是,这种方式有一个问题,此应用依然不是运行在系统进程中,他依然是独立的进程。我们无法获得系统进程中的一些参数。如何解决这种需求呢?</span></span></p>
<p><span style="color: rgba(22, 145, 121, 1)"><span style="color: rgba(0, 0, 0, 1)"> 一些人会直接在ActivityManagerService、PowerManagerService、PhoneWindowManager 中直接修改或者增加代码,用广播的形式传递到应用层。但是这种方式问题很多,首先需要修改这些代码量超级多的原生服务,一不小心很容易出现问题。</span></span></p>
<p><span style="color: rgba(22, 145, 121, 1)"><span style="color: rgba(0, 0, 0, 1)"> 而最好的办法就是我们也添加一个系统级服务,提供给外部使用,而在这个服务中,我们可以通过直接调用相关服务实现需求。</span></span></p>
<h1><span style="color: rgba(22, 145, 121, 1)">第一步创建AIDL文件</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">创建位置:frameworks/base/core/java/android/os/IMySystemService.aidl</span></p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>// IMySystemService.aidl
package android.os;
interface IMySystemService {
String getText(String aString);
}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第二步将AIDL文件添加到Android.bp中</span></h1>
<p>文件路径:frameworks/base/Android.bp</p>
<pre class="language-bash highlighter-hljs" data-dark-theme="true"><code>
java_defaults {
name: "framework-defaults",
installable: true,
srcs: [
// From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
"core/java/**/*.java",
"graphics/java/**/*.java",
"location/java/**/*.java",
"lowpan/java/**/*.java",
"media/java/**/*.java",
"media/mca/effect/java/**/*.java",
"media/mca/filterfw/java/**/*.java",
"media/mca/filterpacks/java/**/*.java",
"drm/java/**/*.java",
"opengl/java/**/*.java",
"sax/java/**/*.java",
"telecomm/java/**/*.java",
"telephony/java/**/*.java",
"wifi/java/**/*.java",
"keystore/java/**/*.java",
"rs/java/**/*.java",
":framework-javastream-protos",
//略.............
"core/java/android/speech/tts/EventLogTags.logtags",
"core/java/android/net/EventLogTags.logtags",
"core/java/android/os/EventLogTags.logtags",
"core/java/android/webkit/EventLogTags.logtags",
"core/java/com/android/internal/app/EventLogTags.logtags",
"core/java/com/android/internal/logging/EventLogTags.logtags",
"core/java/com/android/server/DropboxLogTags.logtags",
"core/java/org/chromium/arc/EventLogTags.logtags",
":apex-properties",
":platform-properties",
":framework-statslog-gen",
//在此处添加IMySystemService.aidl的路径
"core/java/android/os/IMySystemService.aidl",
],
//略....................</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第三步创建service文件</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">创建位置: frameworks/base/services/core/java/com/android/server/MySystemService.java</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">请主意下面的package 路径,不可以随便修改。</span></p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>package com.android.server;
import android.os.IMySystemService;
import android.os.IBinder;
import android.os.RemoteException;
import android.content.Context;
import android.util.Log;
public class MySystemService extends IMySystemService.Stub{
private Context mContext;
public MySystemService(Context context){
mContext = context;
Log.v("zhou", "MySystemService is init");
}
@Override
public String getText(String aString) throws RemoteException {
return aString;
}
}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第四步在SystemServer添加服务,使其开机就启动服务</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">文件路径:/aosp/frameworks/base/services/java/com/android/server/SystemServer.java</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">SystemServer是Android系统中用于启动service的入口。在Android系统启动时,会启动两个重要的进程,一个是Zygote进程,另一个是由Zygote进程fork出来的system_server进程。SystemServer会启动我们在系统中所需要的一系列service。</span></p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>package com.android.server;
//别忘记这里添加引用
import com.android.server.MySystemService;
public final class SystemServer {
private static final String TAG = "SystemServer";
/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored and organized.
*/
private void startOtherServices() {
final Context context = mSystemContext;
//略....................
// We now tell the activity manager it is okay to run third party
// code.It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.
mActivityManagerService.systemReady(() -> {
//略......
}, BOOT_TIMINGS_TRACE_LOG);
//在此处添加代码
try{
ServiceManager.addService(Context.MY_SYSTEM_SERVICE, new MySystemService(context));
} catch(Throwable e){
Slog.e(TAG, "Failure starting MySystemService", e);
}
}
}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第五步创建提供外部调用的服务管理</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">创建位置:frameworks/base/core/java/android/app/MySystemServiceManager.java</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">请主意下面的package 路径,不可以随便修改。</span></p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>package android.app;
import android.os.IMySystemService;
import android.os.RemoteException;
public class MySystemServiceManager {
private IMySystemService mService;
public MySystemServiceManager(IMySystemService service){
mService = service;
}
public String getText(String text){
try {
return mService.getText(text);
} catch (RemoteException e) {
e.printStackTrace();
}
return "";
}
}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第六步在Context增加属性</span></h1>
<p>路径:frameworks/base/core/java/android/content/Context.java</p>
<p>如下列图,共2处添加:</p>
<p>第一处,添加常量</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204112634359-844883890.png"></p>
<p>第二处</p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>/** @hide */
@StringDef(suffix = { "_SERVICE" }, value = {
POWER_SERVICE,
//省略此处代码......
PERMISSION_SERVICE,
MY_SYSTEM_SERVICE,//这里添加上面的常量
})
@Retention(RetentionPolicy.SOURCE)
public @interface ServiceName {}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第七步在SystemServiceRegistry上注册服务管理</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">文件路径:/aosp/frameworks/base/core/java/android/app/SystemServiceRegistry.java</span></p>
<pre class="language-java highlighter-hljs" data-dark-theme="true"><code>//请别忘记import
import android.os.IMySystemService;
import android.app.MySystemServiceManager;
final class SystemServiceRegistry {
private static final String TAG = "SystemServiceRegistry";
//省略此处代码.............
static {
//CHECKSTYLE:OFF IndentationCheck
//省略此处代码.............
registerService(Context.DYNAMIC_SYSTEM_SERVICE, DynamicSystemManager.class,
new CachedServiceFetcher<DynamicSystemManager>() {
@Override
public DynamicSystemManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(
Context.DYNAMIC_SYSTEM_SERVICE);
return new DynamicSystemManager(
IDynamicSystemService.Stub.asInterface(b));
}});
// 在static代码块的最下面新增自己的服务管理MySystemServiceManager
registerService(Context.MY_SYSTEM_SERVICE, MySystemServiceManager.class,
new CachedServiceFetcher<MySystemServiceManager>() {
@Override
public MySystemServiceManager createService(ContextImpl ctx)
throws ServiceNotFoundException {
IBinder b = ServiceManager.getServiceOrThrow(Context.MY_SYSTEM_SERVICE);
return new MySystemServiceManager(IMySystemService.Stub.asInterface(b));
}});
//CHECKSTYLE:ON IndentationCheck
}</code></pre>
<h1><span style="color: rgba(22, 145, 121, 1)">第七步selinux配置策略</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">这是最复杂的一步,需要特别耐心与仔细,任何的错误配置都能导致无法编译成功。</span></p>
<h2><span style="color: rgba(35, 111, 161, 1)">配置service_contexts文件</span></h2>
<p><span style="color: rgba(0, 0, 0, 1)">一共有两处需要配置service_contexts,此外这两处的service_contexts文件在配置后需要一模一样。</span></p>
<h3><span style="color: rgba(53, 152, 219, 1)">第一处</span></h3>
<p>文件路径: /aosp/system/sepolicy/private/service_contexts 在此文件中增加如下。 </p>
<pre class="language-bash highlighter-hljs" data-dark-theme="true"><code>my_system u:object_r:my_system_service:s0</code></pre>
<p>这个可以根据你的服务名称修改,<span style="color: rgba(186, 55, 42, 1)"><strong>最关键的地方是这里的my_system需要与上面的Context中配置的属性一致。 此外其中</strong><strong>my_system_service也是非常关键的,这个与下面的其他项配置有关。</strong></span></p>
<p>增加的位置,如下图:</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204135704419-1496808285.png"></p>
<h3><span style="color: rgba(53, 152, 219, 1)">第二处</span></h3>
<p>文件路径: /aosp/system/sepolicy/prebuilts/api/29.0/private/service_contexts 与上面一样在文件中增加一样的内容,注意!这里的添加的位置也要一模一样。如下图:</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204140447224-1874703007.png"></p>
<h2><span style="color: rgba(35, 111, 161, 1)">配置service.te文件</span></h2>
<p>一共有两处文件需要配置service.te, <span style="color: rgba(0, 0, 0, 1)">此外这两处的service.te文件在配置后需要一模一样</span></p>
<h3><span style="color: rgba(53, 152, 219, 1)">第一处</span></h3>
<p>文件路径:/aosp/system/sepolicy/public/service.te 在此文件中增加:</p>
<pre class="language-bash highlighter-hljs" data-dark-theme="true"><code>type my_system_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;</code></pre>
<p><span style="color: rgba(0, 0, 0, 1)"><strong>请注意!这里最关键的是<span style="color: rgba(186, 55, 42, 1)">my_system_service</span>需要与上面的service_contexts文件中这部分 u:object_r:<span style="color: rgba(186, 55, 42, 1)">my_system_service</span>:s0 的配置的一样。</strong></span></p>
<p><span style="color: rgba(0, 0, 0, 1)">上面的配置,可以更改的api类型上面是app_app_service,如果你不想暴露给普通应用可以改成system_api_service,然后在删除ephemeral_app_api_service,这样就成了系统级服务api了</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">增加的位置,如下图:</span></p>
<p><span style="color: rgba(0, 0, 0, 1)"><strong><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231205182115308-2096335866.png"></strong></span></p>
<h3><span style="color: rgba(53, 152, 219, 1)">第二处</span></h3>
<p>文件路径: /aosp/system/sepolicy/prebuilts/api/29.0/public/service.te 与上面一样在文件中增加一样的内容,注意!这里的添加的位置也要一模一样。如下图:</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231205182210233-602788377.png"></p>
<h2><span style="color: rgba(35, 111, 161, 1)">忽略安全策略,配置ignore.cil后缀文件</span></h2>
<p class="">ignore.cil 后缀文件是一个用于忽略特定安全策略的文件。它通常与Android的安全模型和权限管理相关联。</p>
<p class="">在Android操作系统中,为了保护应用程序和系统的安全,系统会执行一系列的安全策略。这些策略包括权限管理和应用程序隔离等措施。然而,有时候某些应用程序可能需要访问一些被禁止或限制的资源或执行某些被禁止的操作。</p>
<p class="">如下路径的文件都要修改,<strong><span style="color: rgba(186, 55, 42, 1)">请注意!</span>这几个文件的内容不是一样的,所以需要单独一个一个的去添加配置。不可以偷懒全部复制过去。</strong></p>
<ul>
<li>/aosp/system/sepolicy/private/compat/26.0/26.0.ignore.cil</li>
<li>/aosp/system/sepolicy/private/compat/27.0/27.0.ignore.cil</li>
<li>/aosp/system/sepolicy/private/compat/28.0/28.0.ignore.cil</li>
<li>/aosp/system/sepolicy/prebuilts/api/29.0/private/compat/26.0/26.0.ignore.cil</li>
<li>/aosp/system/sepolicy/prebuilts/api/29.0/private/compat/27.0/27.0.ignore.cil</li>
<li>/aosp/system/sepolicy/prebuilts/api/29.0/private/compat/28.0/28.0.ignore.cil</li>
</ul>
<p>需要添加的内容与位置:</p>
<p><strong><span style="color: rgba(186, 55, 42, 1)">my_system_service</span></strong>需要与上面的service_contexts文件中这部分 u:object_r:<span style="color: rgba(186, 55, 42, 1)">my_system_service</span>:s0 的配置的一样。</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204150744902-1781201192.png"></p>
<h1><span style="background-color: rgba(255, 255, 255, 1); color: rgba(22, 145, 121, 1)">第八步编译与验证结果</span></h1>
<h2><span style="color: rgba(35, 111, 161, 1)">编译部分</span></h2>
<p>在编译前记得先执行make installclean ,接着在执行make update-api, 最后在make。</p>
<h2><span style="color: rgba(35, 111, 161, 1)">验证结果</span></h2>
<p>用adb验证</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204153311385-1468950229.png"></p>
<p> 抓log验证,前面的<span style="color: rgba(0, 0, 0, 1)">MySystemService的构造方法中,我增加了一个log</span></p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231204153352424-1309210487.png"></p>
<h1><span style="color: rgba(22, 145, 121, 1)">扩展:在应用中调用我们自己添加的系统服务</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">在应用中调用系统服务,首先得知道如何将<strong>framework架包到应用中</strong>。 这部分知识,请参考我的个人博客 :https://www.cnblogs.com/guanxinjing/p/16613716.html</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">然后我们在一个应用项目中调用代码,如下图:</span></p>
<p><span style="color: rgba(0, 0, 0, 1)"><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231205182625196-1959767595.png"></span></p>
<p>上面红色提示错误的代码,请直接无视,因为framework架包无法避免Android studio不提示错误。 我们只需要Android studio能编译成功apk就行。</p>
<p>应用运行的效果图:</p>
<p><img src="https://img2023.cnblogs.com/blog/1497956/202312/1497956-20231205183004131-820052940.gif" alt="" height="818" width="482"></p>
<h1><span style="color: rgba(22, 145, 121, 1)">关于selinux配置的额外内容</span></h1>
<p><span style="color: rgba(0, 0, 0, 1)">如果有人依然不明白如何配置selinux或者是项目上压根就没需求,这边可以直接通过关闭selinux权限。就可以直接调用服务了</span></p>
<p><span style="color: rgba(0, 0, 0, 1)">关闭服务如下, 将0改成1,可以设置成开启服务</span></p>
<pre class="language-bash highlighter-hljs" data-dark-theme="true"><code>$adb shell
#setenfore 0</code></pre>
<p>查询selinux权限当前状态,Permissive为关闭状态</p>
<pre class="language-bash highlighter-hljs" data-dark-theme="true"><code>my_device_01:/ # getenforce
Permissive</code></pre>
<p>end</p>
</div>
<div id="MySignature" role="contentinfo">
<div style="text-align: center">
<p style="color:orange;font-size:16px;" >本文来自博客园,作者:观心静 ,转载请注明原文链接:https://www.cnblogs.com/guanxinjing/p/17872077.html </p>
<div style="color:orange;font-size:16px;">本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。 </div>
</div><br><br>
来源:https://www.cnblogs.com/guanxinjing/p/17872077.html
頁:
[1]