Android system Modifies ordinary applications without source code to default Launcher and hides the application information icon in Settings

In Android system customization development, sometimes we need to implement some special functions, such as changing the application to the default launcher, or hiding the application icon so that users cannot directly launch or uninstall the application. These functions may be used in some customized scenarios, such as smart TVs, digital signage, etc. But if we don’t have the source code, it’s not that easy to implement these functions (mainly because Shabi customers are unwilling to change). Because the Android system has some restrictions and protection mechanisms for these functions, we need to bypass these restrictions to achieve our goals.

In this article, I will introduce how to modify the application as the default launcher and hide the application icon in the Android system. These methods are based on no source code. You only need to modify part of the system pms parsing Androidmanifes.xml parsing logic. Of course, these methods may not be universal and may differ on different devices and system versions. They need to be adjusted and tested according to specific circumstances. I am just providing ideas here.

Reference study:

Android 11 PackageManagerService source code analysis (1): overall process of PMS startup
Analysis of PMS working principle-parsing process of app directory (Android12)

Simple analysis of PMS analysis part

PMS (PackageManagerService) is the core service responsible for managing applications in the Android system. Its main functions include:

  • Parse and install application apk files, including system applications and user applications
  • Maintain application information and status, including package name, version, permissions, signatures, components, etc.
  • Match appropriate components according to Intent filters, such as Activity, Service, Provider and Receiver, etc.
  • Check application permissions and signatures to ensure system security and consistency
  • Provide the PackageManager interface for other applications or services to call to obtain or modify application-related information

android11 + has made some reconstruction and optimization of the parsing part of pms, separated some classes and methods from PackageManagerService and PackageParser, and placed them under the parsing package and component package.

frameworks/base/core/java/android/content/pm/ folder

There are mainly the following categories under the parsing package:

  • ParsingPackage: This is an interface that defines a collection of basic information and components of an application, equivalent to the original Package object.
  • ParsingPackageImpl: This is the implementation class of the ParsingPackage interface that provides some constructors and auxiliary methods.
  • ParsingPackageRead: This is an abstract class inherited from ParsingPackageImpl, which provides some read-only methods for obtaining application information and components.
  • ParsingPackageUtils: This is a tool class that provides some static methods for obtaining or converting some data from the ParsingPackage object.
  • ParsingUtils: This is a tool class that provides some static methods for parsing or verifying some data.

There are mainly the following classes under the component package:

  • ParsedComponent: This is an abstract class that defines the basic information of an application component, equivalent to the original Component object.
  • ParsedComponentUtils: This is a tool class that provides some static methods for obtaining or converting some data from the ParsedComponent object.
  • ParsedActivity, ParsedService, ParsedProvider, ParsedInstrumentation: These are subclasses of ParsedComponent, corresponding to Activity, Service, Provider and Instrumentation components respectively.
  • ParsedActivityUtils, ParsedServiceUtils, ParsedProviderUtils, ParsedInstrumentationUtils: These are tool classes that provide some static methods for obtaining or converting some data from the corresponding component objects.
  • ParsedIntentInfo: This is a class that defines information about an Intent filter, equivalent to the original IntentFilter object.
  • ParsedIntentInfoUtils: This is a tool class that provides some static methods for parsing or verifying Intent filters.
  • ParsedMainComponent: This is an abstract class that inherits from ParsedComponent and implements the Parcelable interface to represent components that can be started through Intent.
  • ParsedMainComponentUtils: This is a tool class that provides some static methods for getting or converting some data from the ParsedMainComponent object.
  • ParsedPermission, ParsedPermissionGroup: These are classes, corresponding to the Permission and PermissionGroup components respectively.
  • ParsedPermissionUtils: This is a tool class that provides some static methods for parsing or verifying permission components.
  • ParsedProcess: This is a class that defines information about a process.
  • ParsedProcessUtils: This is a tool class that provides some static methods for obtaining or converting some data from ParsedProcess objects.

The above is the function and relationship of the main files under the parsing package and the component package.

Modify the application as the default Launcher

Launcher is a desktop application of the Android system, responsible for displaying and launching other applications. Normally, the system will have a default Launcher, and customers can also download and install other Launchers from the app store. When a customer installs multiple Launchers, the system will pop up a selection box allowing the customer to choose which Launcher to use, and can set whether to remember this choice.

If we want to make our own developed application the default Launcher without letting users choose or change it, we can do this through the following steps:

  1. In our app’s AndroidManifest.xml file, add the following Intent filter to the main Activity:
<intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.HOME" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

This allows our application to respond to click events on the HOME key and launcher icon.

  1. Add the following content to our system source code mk or prop file:
persist.custom_package.launcher=true
persist.custom_package.name=com.example.myapp

persist.custom_package.launcher is a switch attribute, indicating whether to enable the function of modifying the Launcher without source code; persist.custom_package.name is the package name of our application.

If you want to modify the non-source application implementation settings to add the HOME attribute, find the parseIntentInfo method in the frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java file, and Add the following code to it:

launcherProperty = SystemProperties.get("persist.custom_package.launcher", "");
customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
customClassNameProperty = SystemProperties.get("persist.custom_package.classname", "");


// ...

case "category": {<!-- -->
    String value = parser.getAttributeValue(PackageParser.ANDROID_RESOURCES,
            "name");
    // Added code goes here
    if (launcherProperty.equals("true") & amp; & amp; customPackageProperty.equals(className)) {<!-- -->
        intentInfo.addCategory("android.intent.category.HOME");
        intentInfo.addCategory("android.intent.category.DEFAULT");
        intentInfo.setPriority(1000);
    }
    // So far
    if (value == null) {<!-- -->
        result = input.error("No value supplied for <android:name>");
    } else if (value.isEmpty()) {<!-- -->
        result = input.error("<android:name> has empty value");
    } else {<!-- -->
        intentInfo.addCategory(value.intern());
    }
    break;
}

The purpose of this code is to read the system properties, determine whether to add the HOME and DEFAULT categories to the Activity with the specified package name based on the property values, and set the priority to 1000 (the highest). In this way, the Activity can become the Launcher that HOME is added to.

In this way, the application can respond to the Home button and power-on events, and in conjunction with my article (Android System Sets Third-Party Applications as Default Launcher Implementation and Principle Analysis) and will not be replaced by other Launchers.

Even if you don’t add my other article about setting the default forced lock launcher, a pop-up will pop up for you to select manually.

Hide application icon

Sometimes, we may need to hide some application icons so that they do not appear in Launcher. For example, some system services or auxiliary functions, etc. In this case, we can implement the following steps:

  1. In our app’s AndroidManifest.xml file, add the following properties to the main Activity:
android:enabled="false"

 <activity
            android:name=".view.MainActivity"
            android:exported="true" android:theme="@style/Theme.AppCompat.Light.NoActionBar"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
               <!-- Add -->
                <data android:name="com.custom.package.CustomActivity" ></data>
            </intent-filter>
        </activity>

This will prevent our application from being displayed.

2. Add the following content to our system source code mk or prop file or manually setprop settings:

persist.custom_package.hide_icon=true
persist.custom_package.name=com.example.myapp

persist.custom_package.hide_icon is a switch attribute, indicating whether to enable the function of hiding icons without source code; persist.custom_package.name is the package name of our application.

  1. In the frameworks/base/core/java/android/content/pm/parsing/component/ParsedIntentInfoUtils.java file, find the parseIntentInfo method and add the following code in it:
launcherProperty = SystemProperties.get("persist.custom_package.launcher", "");
hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "");
customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
excludeFromRecentsProperty = SystemProperties.get("persist.custom_package.exclude_from_recents", "");
screenOrientationProperty = SystemProperties.get("persist.custom_package.screen_orientation", "");
customClassNameProperty = SystemProperties.get("persist.custom_package.classname", "");
Log.d("pms_test", "launcherProperty:" + launcherProperty + "," + hideIconProperty + "," + hideIconProperty + "," + customPackageProperty + "," + screenOrientationProperty);

// ...

case "data":
    /*if (hideIconProperty.equals("true") & amp; & amp; customClassNameProperty.equals(className)) {
        intentInfo.addDataScheme("com.custom.package");
        intentInfo.addDataAuthority("CustomActivity", null);

        intentInfo.addDataAttribute("android:name", "com.custom.package.CustomActivity");
    }*/
    result = parseData(intentInfo, res, parser, allowGlobs, input);
    break;

The purpose of this code is to read system properties and determine whether to add a custom data filter to the Activity with the specified class name based on the property value. In this way, the Activity will not be matched by the Launcher and the icon will not be displayed. Note that this code is commented out because it will cause some problems, such as being unable to start the Activity or etc. Therefore, this function is only used as a demonstration and is not recommended to be used (I haven’t studied it yet…).

Hide the application display of Settings application management

In addition to hiding app icons and notifications, we may also need to hide some app information so that they do not appear in the app management list. For example, some system services or auxiliary functions, etc. In this case, we can implement the following steps:

  1. Add the following content to our system source code mk or prop file or manually setprop settings:
persist.custom_package.hide_icon=true
persist.custom_package.name=com.example.myapp

persist.custom_package.hide_icon is a switch attribute, indicating whether to enable the function of hiding icons and information without source code; persist.custom_package.name is the package name of our application.

  1. In the packages/apps/Settings/src/com/android/settings/applications/manageapplications/ManageApplications.java file, find the updateState method and add the following code in it:
//Import SystemProperties class
import android.os.SystemProperties;

//Define two static variables to store the values of system properties respectively.
private static String hideIconProperty;
private static String customPackageProperty;

@Override
public void onCreate(Bundle savedInstanceState) {<!-- -->
    super.onCreate(savedInstanceState);
    // ...
    // Read the system properties in the onCreate method and assign them to static variables
    hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "true");
    customPackageProperty = SystemProperties.get("persist.custom_package.name", "com.btf.rk3568_11_fw");
}

private void updateState() {<!-- -->
    // ...
    if (filterType == FILTER_APPS_POWER_WHITELIST ||
            filterType == FILTER_APPS_POWER_WHITELIST_ALL) {<!-- -->
        entries = removeDuplicateIgnoringUser(entries);
    }

    // Traverse the application list. If the package name of an application is the same as the package name specified by the system property and the switch property is true, remove the application from the list.
    for (int i = 0; i < entries.size(); i + + ) {<!-- -->
        AppEntry appEntry = entries.get(i);
        if (hideIconProperty.equals("true") & amp; & amp; customPackageProperty.equals(appEntry.info.packageName)) {<!-- -->
            entries.remove(i);
            i--;
        }
    }
    mEntries = entries;
    mOriginalEntries = entries;
    notifyDataSetChanged();
}

The function of this code is to read the system properties and determine whether to remove the application with the specified package name based on the property value and not add it to the list of application management.

  1. In the packages/apps/Settings/src/com/android/settings/notification/RecentNotifyingAppsPreferenceController.java file, find the displayRecentApps method and add the following code in it:
//Import SystemProperties class
import android.os.SystemProperties;

//Define two static variables to store the values of system properties respectively.
private static String hideIconProperty;
private static String customPackageProperty;

public RecentNotifyingAppsPreferenceController(Context context, NotificationBackend backend,
        IUsageStatsManager usageStatsManager, UserManager userManager,
        Application app, Fragment host) {<!-- -->
    this(context, backend, usageStatsManager, userManager,
            app == null ? null : ApplicationsState.getInstance(app), host);
    //Read the system properties in the constructor and assign them to static variables
    hideIconProperty = SystemProperties.get("persist.custom_package.hide_icon", "");
    customPackageProperty = SystemProperties.get("persist.custom_package.name", "");
}

private void displayRecentApps() {<!-- -->
    // ...
    for (int i = 0; i < recentAppsCount; i + + ) {<!-- -->
        final NotifyingApp app = recentApps.get(i);
        // Bind recent apps to existing prefs if possible, or create a new pref.
        final String pkgName = app.getPackage();
        // If the package name of an application is the same as the package name specified by the system property, and the switch attribute is true, the application will be skipped and will not be displayed in the recent notification application list.
        if (hideIconProperty.equals("true") & amp; & amp; customPackageProperty.equals(pkgName)) {<!-- -->
            continue;
        }
        final ApplicationsState.AppEntry appEntry =
                mApplicationsState.getEntry(app.getPackage(), app.getUserId());
        if (appEntry == null) {<!-- -->
            continue;
        }
        // ...
    }
    // ...
}

The function of this code is to read system properties and determine whether to skip the application with the specified package name based on the property value and not display it in the list of recently notified applications.

Summary

This article describes how to modify the application as the default launcher and hide the application icon on Android 11 without source code. These functions can be achieved by setting some system properties and modifying some configuration files without modifying the source code or recompiling the entire system. Of course, these functions are part of learning PMS. Will the actual use of parts that require a lot of testing and modification affect the system? Therefore, when using these functions, you need to make trade-offs and choices based on specific needs and scenarios.

Hope this article is helpful to you. Thanks!