This article links http://wossoneri.github.io/2018/08/30/[android][framework]crop-systemserver-and-systemfeature/
Systemserver Service Clipping
Some systems, because of the different scenarios, need the same services. Android things, for example, cuts a lot of services in response to IoT scenarios. Here's how to crop a service.
About the service, to mention Systemserver, specific introduction see another article: Http://wossoneri.github.io. Systemserver launched the core services of the system, in addition, Systemserver also launched a number of other services, specifically in the Startotherservices () method. We can start by tailoring the services we don't need.
For example, to turn off the printer service:
You can comment out the code for the related startup service directly:
//mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
Of course, after this modification, if you want to open again later, you also need to modify the Systemserver, and then compile the jar package, push to the device to make it effective.
It is recommended to use the following modification:
First, define the Boolean variable, read the configuration from the global property,
boolean disablePrinter = SystemProperties.getBoolean("config.disable_printer", false);
Then add a judgment on this property in the code snippet that starts the service:
if (!disablePrinter && mPackageManager.hasSystemFeature(PackageManager.FEATURE_PRINTING)) {
mSystemServiceManager.startService(PRINT_MANAGER_SERVICE_CLASS);
}
After that, add the custom system permissions in Makefile:
PRODUCT_PROPERTY_OVERRIDES += \ config.disable_printer=true
If you want to open this service later, turn the true to false.
If you want to debug, modify the device/system/build.propand then restart it. Very convenient to have wood there!
If you want to modify, delete the Build.prop in the Out directory, recompile the system (or modify build.prop and make Snod), and then run the following command to verify it:
service check printer
This will not start the service you don't need anymore.
Issues raised by the cropping service
Service is not you don't let it start on the finish, the system is so big, there are always some places to get the service object to do some call processing. For example, we just cut out the printer service and then opened settings and ran into crash:
E AndroidRuntime: FATAL EXCEPTION: main
E AndroidRuntime: Process: com.android.settings, PID: 3496
E AndroidRuntime: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.settings/com.android.settings.Settings}: java.lang.NullPointerException: Attempt to invoke interface method 'java.util.List android.print.IPrintManager.getPrintServices(int, int)' on a null object reference
E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2665)
E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
E AndroidRuntime: at android.app.ActivityThread.-wrap12(ActivityThread.java)
E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1477)
E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
E AndroidRuntime: at android.os.Looper.loop(Looper.java:154)
E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:6119)
E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:900)
E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:790)
E AndroidRuntime: Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'java.util.List android.print.IPrintManager.getPrintServices(int, int)' on a null object reference
E AndroidRuntime: at android.print.PrintManager.getPrintServices(PrintManager.java:635)
E AndroidRuntime: at android.print.PrintServicesLoader.onStartLoading(PrintServicesLoader.java:88)
E AndroidRuntime: at android.content.Loader.startLoading(Loader.java:290)
E AndroidRuntime: at android.app.LoaderManagerImpl$LoaderInfo.start(LoaderManager.java:283)
E AndroidRuntime: at android.app.LoaderManagerImpl.installLoader(LoaderManager.java:579)
E AndroidRuntime: at android.app.LoaderManagerImpl.createAndInstallLoader(LoaderManager.java:566)
E AndroidRuntime: at android.app.LoaderManagerImpl.initLoader(LoaderManager.java:619)
E AndroidRuntime: at com.android.settings.search.DynamicIndexableContentMonitor.register(DynamicIndexableContentMonitor.java:136)
E AndroidRuntime: at com.android.settings.SettingsActivity.onStart(SettingsActivity.java:868)
E AndroidRuntime: at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1249)
E AndroidRuntime: at android.app.Activity.performStart(Activity.java:6737)
E AndroidRuntime: at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2628)
E AndroidRuntime: ... 9 more
With the stack information, you know that a null pointer appears in Printmanager.getprintservices. There is no need to look at the code here, because we do not start the printing service, so definitely get not to the service.
Then consider modifying the scheme to increase the non-null protection is it possible? naive! Our goal is to crop the print service, so our modification point is not in the service itself, but instead removes the place where this service is called.
So don't change the printmanager,printservicesloader of the stack display, we have to look at the code structure to see how the call came in. By reading the code, I learned that there are many loader types of objects in the system, one of which is printservicesloader. These loader are then initiated by the Loadermanager management. and Loadermanager in Dynamicindexablecontentmonitor.java once initialization operation.
Look at the Dynamicindexablecontentmonitor.java code:
public void register(Activity activity, int loaderId) { ... boolean hasFeaturePrinting = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PRINTING); ... if (hasFeaturePrinting) { activity.getLoaderManager().initLoader(loaderId, null, this); } ...
Have the wood found a familiar code?
Yes, there's another systemfeature in the code! The same judgment was made before Systemserver started the service the last time it occurred.
So to cut out the printer service, we just need to close the feature_printing.
By modifying the Systemfeature judgment, the clipping code inside the Systemserver can no longer be added. But some of the services that crop Android do not add the processing of system features, so it is recommended to use my method for cropping.
Systemfeature Loading process
Take a look at it firstFEATURE_PRINTING
Packagemanager.java
/** * Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}: * The device supports printing. */@SdkConstant (sdkconstanttype.feature) public static final String feature_printing = "Android.software.print";/** * Get a list of features that is available on the * system. * * @return An array of featureinfo classes describing the features * this is available on the system, or null if there a Re None (!!). */public abstract featureinfo[] Getsystemavailablefeatures ()/** * Check whether the given feature name is one of the Avai Lable features as * returned by {@link #getSystemAvailableFeatures ()}. This tests for the * presence of <em>any</em> version of the given feature name; Use * {@link #hasSystemFeature (String, int.)} to check for a minimum version. * * @return Returns True if the devices supports the feature, else false. */public Abstract Boolean hassystemfeature (String name);/** * Check whether the given feature name and version is one of T He available * Features as returned by {@link #getSystemAvailableFeatures ()}. Since * Features is defined to always being backwards compatible, this returns True * if the available feature version is GR Eater than or equal to the * requested version. * * @return Returns True if the devices supports the feature, else false. */public Abstract Boolean hassystemfeature (String name, int version);
Are abstract methods, we go to the PMS to find the corresponding implementation
Packagemanagerservice.java
/**
* Feature for {@link #getSystemAvailableFeatures} and {@link #hasSystemFeature}:
* The device supports printing.
*/ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_PRINTING = "android.software.print"; /**
* Get a list of features that are available on the
* system.
*
* @return An array of FeatureInfo classes describing the features
* that are available on the system, or null if there are none(!!).
*/ public abstract FeatureInfo[] getSystemAvailableFeatures(); /**
* Check whether the given feature name is one of the available features as
* returned by {@link #getSystemAvailableFeatures()}. This tests for the
* presence of <em>any</em> version of the given feature name; use
* {@link #hasSystemFeature(String, int)} to check for a minimum version.
*
* @return Returns true if the devices supports the feature, else false.
*/ public abstract boolean hasSystemFeature(String name); /**
* Check whether the given feature name and version is one of the available
* features as returned by {@link #getSystemAvailableFeatures()}. Since
* features are defined to always be backwards compatible, this returns true
* if the available feature version is greater than or equal to the
* requested version.
*
* @return Returns true if the devices supports the feature, else false.
*/ public abstract boolean hasSystemFeature(String name, int version);
The logic here is to get all the feature through Mavailablefeatures, to find the relevant code for that member variable
public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
synchronized (mPackages) {
final ArrayList<FeatureInfo> res = new ArrayList<>(mAvailableFeatures.values());
final FeatureInfo fi = new FeatureInfo();
fi.reqGlEsVersion = SystemProperties.getInt("ro.opengles.version",
FeatureInfo.GL_ES_VERSION_UNDEFINED);
res.add(fi);
return new ParceledListSlice<>(res);
}
}
@Override
public boolean hasSystemFeature(String name, int version) {
synchronized (mPackages) {
final FeatureInfo feat = mAvailableFeatures.get(name);
if (feat == null) {
return false;
} else {
return feat.version >= version;
}
}
}
learned that you first get an systemconfig singleton, and then get the available feature through the Getavailablefeatures method.
Systemconfig.java
// These are the features this devices supports that were read from the
// system configuration files.
final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();
public ArrayMap<String, FeatureInfo> getAvailableFeatures() {
return mAvailableFeatures;
}
private void addFeature(String name, int version) {
FeatureInfo fi = mAvailableFeatures.get(name);
if (fi == null) {
fi = new FeatureInfo();
fi.name = name;
fi.version = version;
mAvailableFeatures.put(name, fi);
} else {
fi.version = Math.max(fi.version, version);
}
}
private void removeFeature(String name) {
if (mAvailableFeatures.remove(name) != null) {
Slog.d(TAG, "Removed unavailable feature " + name);
}
}
According to Mavailablefeatures's comments, the feature supported by the device is read from the configuration file. The place where the read configuration file is called is:
SystemConfig() {
// Read configuration from system
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "sysconfig"), ALLOW_ALL);
// Read configuration from the old permissions dir
readPermissions(Environment.buildPath(
Environment.getRootDirectory(), "etc", "permissions"), ALLOW_ALL);
// Allow ODM to customize system configs around libs, features and apps
int odmPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_APP_CONFIGS;
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "sysconfig"), odmPermissionFlag);
readPermissions(Environment.buildPath(
Environment.getOdmDirectory(), "etc", "permissions"), odmPermissionFlag);
// Only allow OEM to customize features
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "sysconfig"), ALLOW_FEATURES);
readPermissions(Environment.buildPath(
Environment.getOemDirectory(), "etc", "permissions"), ALLOW_FEATURES);
}
Here it is clear that it is read several directories:
- /system/etc/permission
- /system/etc/sysconfig
- /oem/etc/permission
- /oem/etc/sysconfig
- /odm/etc/permission
- /odm/etc/sysconfig
The XML file is then traversed for parsing. Systemfeature is the parsed feature tag.
Finally, we summarize the loading process:
Shielded Systemfeature
Know the principle is good to do, in the system scan several directories using the grep command to find the control printer string, find:
/system/etc/permission/handheld_core_hardware.xml
<!-- basic system services -->
<feature name="android.software.app_widgets" />
<feature name="android.software.connectionservice" />
<feature name="android.software.voice_recognizers" notLowRam="true" />
<feature name="android.software.backup" />
<feature name="android.software.home_screen" />
<feature name="android.software.input_methods" />
<feature name="android.software.print" /> <------This is the print feature
You can test it on your phone by commenting it out.
However, we also need to modify the source code to ensure that the future compilation of the value of the system is blocked.
Find makefile and find the following:
PRODUCT_COPY_FILES := \ frameworks/native/data/etc/handheld_core_hardware.xml:system/etc/permissions/handheld_core_hardware.xml
The location of this file in the source code isframeworks/native/data/etc/. Find the source file, will not feature comment off, and then recompile the source code, start the system, everything is normal! Printer-related services have been completely blocked out, the system boot speed, resource consumption has become a little bit smaller. Well, it's a little bit small, and we can cut out many services like VR, infra-red, and so on, to fit the thin system under different scenarios.