Cross-Language Android Permission Specification


TheAndroidsystemmanagesaccesstosensitiveAPIsbypermission enforcement. An application (app) must declare proper permissions before invoking specific Android APIs. However, there is no oficial documentation providing the complete list of permission-protected APIs and the corresponding permissions to date. Researchers have spent significant efforts extracting such API protection mapping fromtheAndroidAPIframework,whichleveragesstaticcodeanaly-sistodetermineifspecificpermissionsarerequiredbeforeaccessing an API. Nevertheless, none of them has attempted to analyze the protection mapping in the native library (i.e., code written in C and C++), an essential component of the Android framework that handles communication with the lower-level hardware, such as cameras and sensors. While the protection mapping can be uti-lized to detect various security vulnerabilities in Android apps, such as permission over-privilege, imprecise mapping will lead to false results in detecting such security vulnerabilities. To fill this gap, we thereby propose to construct the protection mapping in-volved in the native libraries of the Android framework to present a complete and accurate specification of Android API protection. We develop a prototype system, named NatiDroid, to facilitate the cross-language static analysis and compare its performance with two state-of-the-practice tools, termed Axplorer [13] and Arcade [9]. We evaluate NatiDroid on more than 11,000 Android apps, including system apps from custom Android ROMs and third-party apps from the Google Play. Our NatiDroid can identify up to 464 new API-permission mappings, in contrast to the worst-case results derived from both Axplorer and Arcade, where approx-imately 71% apps have at least one false positive in permission over-privilege. We have disclosed all the potential vulnerabilities detected to the stakeholders.


ACM Reference Format:

Anonymous Author(s). 2022. Cross-Language Android Permission Specifi-cation. In Proceedings of The 30th ACM Joint European Software Engineering Conference and Symposium on the Foundations of Software Engineering (ES-EC/FSE 2022). ACM, New York, NY, USA, 11 pages. nnnnnnn.nnnnnnn

Figure 1: Android software stack



Android protects access to restricted data (e.g., the device identifier) and actions (e.g., making phone calls) through permission enforce-ment [12]. Such an access control model can protect users against snooping and protect the stability and security of the operating system [31]. When an Android app attempts to access the restricted resources, a security check is triggered to inspect whether proper permissions are granted. Lack of permission request will prevent access to the resource and further cease the corresponding function-ality or even crash the app. Therefore, it is essential for developers to know the permissions required of the invoked API. Unnecessary required permissions can pose three threats: (i) Too many required permissions may confuse users. Users suspect that the app hasunexpected behaviors, which leads to users uninstalling or unwilling to install the app; (ii) The permissions required by an app is an important feature in detecting Android malware. Unnecessary permissions will fool the detector and cause a false alarm; (iii) The app will incur security risks with unnecessary permissions. Once the app contains vulnerabilities that can be injected with tampered code, it is easy for an attacker to thwart user privacy or invoke sensitive APIs. Moreover, requesting unnecessary permissions may expand the attack surface and expose the Android operating system to a host of attacks, especially privilege escalation attacks [17].Therefore, to safeguard users’ privacy and protect the Android ecosystem, Android app developers are suggested to follow the principle of least privilege, i.e., requesting a minimum set of permissions required to fulfill the apps’ functionality. Unfortunately, Android does not provide official documentation for the permission specifications (i.e., a mapping between APIs and the required permissions), making it difficult for app developers to follow the least privilege rule, and further lead to security vulnerabilities such as permission over-privilege [17]. To address this problem, researchers have been working on developing methods that generate an accurate list, called a protection map, that maps Android APIs to the required permissions. The previous works that provide such protection maps include Stowaway [17], PScout [12], Axplorer [13], Arcade [9], PSGen [39], and most recently, Dynamo [14]. Stowaway empirically determines the permissions required in Android APIs using feedback-directed testing. PScout and Axplorer leverage control-flow reachability analysis on the source code of the Android framework to generate the mapping between APIs and permissions. Arcade proposes a path-sensitive method based on graph abstraction techniques to generate a more precise mapping. PSGen statically generatesthe protection map for Android NDK. Dynamo extracts the protection mapping through dynamic test. Dynamic testing methods (e.g., Stowaway and Dynamo) can accurately map the required permissions to API invocations that they have tested; however, such dynamic approaches suffer from an intrinsic shortcoming of low coverage. The existing static analysis based approaches (e.g., PScout, Axplorer, and Arcade) have better coverage but may lead to imprecise results because of improper modeling of the complicated Android communication mechanisms. PSGen extracts protection mapping for Android NDK (i.e., both protected APIs and permission checks are in the Native code), which has a different scope to our approach (i.e., the protected APIs are in the Java framework, while the permission checks are in the Native code).

Specifically, existing works only analyzed the Java API framework in the Android API Framework, but overlooked the C/C++ Native Library that consists of core Android system components and services (e.g., Camera service, Sensor service). For example, the public method openCamera() in class implements its permission check (“android.permission.CAMERA”) in the native library CameraService.cpp. Missing native library analysis will mistakenly conclude that the API openCamera() does not require any permissions (one example is detailed in Section 2). While the API-permission protection mapping contributes to identifying security vulnerabilities in Android apps, such as permission over-privilege [17] (i.e., an app requests additional permissions that are not required), the imprecise mapping will lead to false results on detecting such vulnerabilities. Taking the aforementioned case as an example, an app invokes the API openCamera() will need to request the corresponding permission android.permission.CAMERA; however, existing works that do not analyze the native libraries will identify it as a permission overprivilege case, and henceforce, a false positive. Static analysis is widely used in code analysis due to its fast speed and high code coverage, especially in the field of Android security analysis [11, 21, 22, 24, 26, 27, 32, 38]. There are also many works on vulnerability identification of Android operation systems [10, 15, 16, 23, 25, 28–30, 33, 35]. In this research, to address the shortcomings of the existing works, we leverage the cross-language analysis on the overall Android system, including both the Java API Framework and the C/C++ Native Libraries. To this end, we analyze the cross-language communication mechanisms on five Android Open Source Projects (AOSP) and summarize two communication models to facilitate the cross-language analysis. We develop a prototype system, NatiDroid, and generate Native-triggered (i.e., an Android API whose permission check is implemented in the native library) API-permission mappings in AOSP versions 7.0, 7.1, 8.0, 8.1, and 10.0, which were chosen to benchmark against prior works [9, 13] (see detailed discussion in Section 5). In addition to the mappings generated by previous works, Axplorer and Arcade (2,115 and 1,585, respectively, in AOSP 7.0), NatiDroid can successfully discover 449 mappings that are not covered previously.

Note that while most Android APIs are Java methods, fewer of them are C/C++ methods. Nevertheless, these native methods play indispensable roles in the Android system, such as interacting with the hardware layer. We further use the new mappings to detect permission over-privilege vulnerabilities on a large dataset containing more than 11,000 Android apps, including system apps from custom Android ROMs and third-party apps from the Google Play. We identify the worst-case scenario, where approximately 71% apps with permission over-privilege detected by Axplorer and Arcade are false positives. In summary, we make the following contributions:

• We design and implement a prototype system, NatiDroid, to

facilitate cross-language control-flow analysis on the Android

framework. To the best of our knowledge, this is the first work

to enable cross-language analysis on the Android framework.

By incorporating NatiDroid with existing Java-side permission

mappings (e.g., Axplorer or Arcade), we obtain a complete per

mission mapping that covers the entire Android system. We make

our system and results publicly available to benefit researchers

and practitioners.1

• We apply NatiDroid to extract the permission-API protection mappings from the native libraries on four AOSP versions (7.0, 7.1, 8.0, 8.1, and 10.0). We show that 12 permissions, including 8 signature and 2 dangerous permissions, are determined to be enforced in native libraries, which are not covered by two state of-the-practice benchmarks, Axplorer and Arcade.

• We analyze Android apps for permission over-privilege. Our results show that NatiDroid is effective in identifying vulnerable Android apps. We have identified approximately 71% false positives in terms of the number of the apps with at least one permission over-privileged.

We hope that the proposed system, NatiDroid in this paper could bridge the gap between Java- and Native-sides analysis (see Figure 1), rendering the static analysis of the overall Android framework to be complete and accurate.


This section provides background information on how Android OS operates and explains the limitations of the existing static API protection mapping generation techniques that motivate our work. Android framework. Android framework consists of the Java API Framework layer and C/C++ Native Library layer (i.e., the second and the third layers from the top in Figure 1). The Java API Framework layer offers Application Programming Interfaces (APIs) written in the Java language for Android app developers to access Android features and functionalities. The Java framework access the device hardware capabilities, such as the camera and sensors, via the C/C++ Native Library layer. When a Java framework API (e.g., the Camera Manager in Figure 1) invokes a call to access device hardware, the Android system loads corresponding library module (e.g., the Camera Service) for that hardware component.

Android permission model. When an app needs to use any of the protected features of an Android device (e.g., accessing the camera, sending an SMS, making a phone call), it must obtain the appropriate permission(s) from the user. When an Android API is called, the Android framework checks whether it is protected by any permission. Most of such permission checks are defined in the Java API Framework layer in the Android system, while there are yet a number of them defined in the C/C++ Native Library layer.

Existing works [9, 12, 13] leverage static analysis on the Java API Framework layer of the Android framework to extract the mapping between APIs and corresponding permission checks. Ignoring the invocation of native libraries miss the permission checks in the native libraries, leading to incomplete mapping results.

Figure 2: Motivation example derived from a real-world Android app vStudio.Android.Camera360. The code is simplified for better illustration.
Figure 2: Motivation example derived from a real-world Android app vStudio.Android.Camera360. The code is simplified for better illustration.

Motivating example. We further elaborate on our motivation with a real-world example illustrated in Figure 2. The code from lines 1 to 10 is derived from a popular photography app vStudio.Android.Camera360 [8] on Google Play. The app initialises a CameraManager instance (line 4), and opens the camera instance by invoking openCamera() method (line 8). The invocation chain then traverses along the call path through an Android SDK class (lines 11 to 18) and a native library CameraService.cpp (lines 19 to 32), and finally triggers a permission check in the native library (line 28). Note that the cameraService.connectDevice() (line 18) communicates with the CameraService::connectDevice() (line 20) in a cross-language way (marked as purple). The security check examines if the method is called by its own process (i.e., cameraservice, hence, no permission is required) or the corresponding permission android.permission.CAMERA is granted. If neither it is called from its own process, nor the android.permission.CAMERA permission is granted, a permission denied error is returned (line 30), which will further prevent openCamera() to be executed. This example implies a protection mapping from the Android API, CameraManager.openCamera(), to itspermission protection check, {android.permission.CAMERA || callingPid == getpid()}.2

Unfortunately, as existing works only analyzed the Java source code in the Android framework, they miss the permission checks implemented in the native libraries. For instance, the mapping of the API CameraManager.openCamera() to the permission android.permission.CAMERA, as shown in the example, does not exist in the state-of-the-practice works, such as PScout [12], Axplorer [13], or Arcade [9]. The incompleteness of the mapping results further introduces false results in detecting security vulnerabilities, such as permission over-privilege [17] (detailed in Section 4.3)


We propose and implement a prototype system, NatiDroid, to address the cross-language protection mapping problem that has long been overlooked in previous works. Figure 3 illustrates the overall design of NatiDroid. As depicted, NatiDroid contains three modules. The Pre-processing module prepares the intermediate artifacts for analyzing the Android framework and native libraries, such as intermediate .jar files (for Java-side analysis) and Clang compile commands (for Native-side analysis). The Entry-points identification module summarizes two cross-language communication models used in the Android framework, and identifies the entry-points for both Java- and Native-sides analysis. The Cross-language Control Flow Graph (CFG) analysis module constructs the cross-language CFG and extracts the permission mapping.

We propose a complete solution for extracting Native-triggered permission mapping from the Android system. We leverage Soot [1] and Clang [2] static analysis frameworks, although our solution is also applicable to other static analysis frameworks. Soot is a popular Java optimization framework for analyzing and visualizing Java and Android apps, which has been widely used in various projects for static analysis [12, 18, 19]. Clang is a lightweight compiler for C language family. We use Clang to transform C/C++ code to the Abstract syntax tree (AST) [3]. Additional code for implementing NatiDroid consists of approximately 7kLOC. We detail the design and implementation of each module in the following subsections.

3.1 Pre-processing

Due to the complexity and cross-language nature of the Android framework, there is no off-the-shelf tool for static analysis of the Android framework (i.e., Java API Framework and Native Library) as a whole. NatiDroid leverages the divide-and-conquer strategy to facilitate the Java- and Native-sides analysis. However, there are still non-trivial tasks to prepare the AOSP codebase for the static analysis. Hence, in this module, we prepare the intermediate artifacts from the AOSP codebase, which are required to enable the Java- and Native-sides analysis. Note that the pre-processing module includes most engineering works, which is not considered our technical contribution. However, it is essential to facilitate the proposed cross-language analysis.

Figure 3: An overview of NatiDroid system


Java-side analysis preparation. NatiDroid’s Java-side analysis takes compiled .jar file as input. However, to maintain the stability of the Android system, some non-SDK class and method bodies are hidden using the @hidden Javadoc tag (e.g., non-SDK Android APIs that may be changed in the future versions without noticing the app developer) during the building of android.jar from source code. The hidden classes and methods only expose the method name, parameters, return values, and minimum set of statements required to handle the invocation, which is not sufficient for constructing a complete CFG. We therefore retain the intermediate output during the compilation, i.e., the intermediate .jar files that have not been combined as android.jar. These intermediate .jar files, such as, have the complete class and method information sufficient for facilitating static analysis.

Native-side analysis preparation. Before we build the crosslanguage CFG (cf. Section 3.3), we leverage Clang to transform C/C++ source code to AST. A complete set of Clang compile command is required to enable the static analysis, however, is not provided in Android documentation. Android uses the ninja to build system [6]. During the compilation process, the .ninja files containing ninja build commands are generated by the compiler.

However, the commands obtained from .ninja files consist of file operations and a mixture of GNU Compiler Collection (GCC) and Clang commands, which are not compatible with the off-the-shelf Clang-based analyzer. We then develop a system (to 500 LOC) to extract and pre-process the required commands from these files. The functions of the system include merging separated ninja commands and replacing the Clang++ commands with Clang commands (i.e., adding C++ headers in Clang command’s parameters).

3.2 Entry-Points Identification

Recall that the overall idea of generating a protection mapping is to examine whether the invocation of an API will trigger a permission check in the Android framework (i.e., if there is a permission check node in the CFG starting from the API call). Due to the complexity of the Android framework, building a CFG of the overall framework is neither practical nor efficient. As NatiDroid’s goal is to complement the existing mappings, such as Axplorer and Arcade, by adding the protections whose permission checks are located in the native libraries, we only generate sub-CFGs for the Android APIs that involve cross-language communication. The first step to generate sub-CFGs is to identify the entry-points of the graphs (for both Java- and Native-sides). To this end, we first summarize two cross-language communication mechanisms used by Android.

Figure 4: AIDL communication model. The Java-side caller invokes remote method from Native-side.


AIDL-based communication model. The Android operating system (OS) is based on Linux but does not inherit the Inter-Process Communication (IPC) mechanism of Linux. In Android, resources between processes are not shared. Android Interface Definition Language (AIDL) is one of the IPC mechanisms that Android adopted to enable communication for remote invocation, providing crossprocess or even cross-language communication. Figure 4 depicts the workflow of AIDL-based client-service model, where the Java framework works as a client requesting service from the native library. AIDL utilizes a pair of Stub/Proxy classes on Java-side to communicate with native libraries. The Proxy is responsible for sending requests to native service and implementing the remote method which invokes the transact() method and communicates with Native-side, while the Stub class, inheriting the Binder class, transforms service Binder and receives the reply from native service using the method onTransact(). The transact() and on Transact() are synchronous, such that a call to transact() does not return until the target has returned from onTransact().

On Native-side, it is unnecessary to generate Stub/Proxy pairs, but directly implements the remote method (using the name as same as the remote method on Java-side) to handle the request from Java-side, so that we can always find the receiver on Transact() and the same name remote method as the AIDL sender. Through using pairs of onTransact() and transact() methods as sender and receiver on both sides, the communication between Java- and Native-sides is established. Therefore, cross-language interaction can be detected via matching the use of AIDL on Java- and Nativesides (e.g., the Stub/Proxy pair, the onTransact() methods, and the implementation of the remote methods and the transact() methods). We can then determine the entry-points for static analysis accordingly.

Figure 5: An example of AIDL-based cross-language communication model. The code snippets are simplified for better illustration.


An example of AIDL mechanism is shown in Figure 5, where the method getCameraInfo() uses AIDL to implement the communication between Java and C++. A pair of a sender and a receiver on each side of AIDL (i.e., the client and the service) handles the cross-language communication. The caller (line 3) invokes the method getCameraInfo() which is firstly defined as an interface in line 6 and then implemented in line 14 (the detailed implementation is omitted). In the corresponding native library (lines 16 to 24), the receiver onTransact() handles the request and further invokes the method getCameraInfo() (line 23). The get CameraInfo() method then executes the method implementation and sends the execution result back to the Java-side onTransact() method (line 9), which is further passed back to the caller (line 3). Note that the getCameraInfo() in line 6 and the getCameraInfo() in line 18 are the two interface methods that both invoke the transact() method (omitted) to establish the communication between Java- and Native-sides. The NatiDroid will match the pair of such remote methods and recognize them as a pair of Java entry-point and native entry-point. Note that, for the inner-language AIDL communication on both Java- and Native-sides, NatiDroid generates CFG with a similar approach, except for the identification of entry-points.

JNI-based communication model. Java Native Interface (JNI) provides a cross-language interface between Java and Native code written in C/C++). This enables developers to write native methods to handle situations when an app cannot be written entirely in the Java programming language, e.g., when the standard Java class library does not support the platform-specific features or program library, such as communication with the underlying hardware. In the JNI framework, native functions are implemented in .c or .cpp files. When invoking the function, it passes a JNIEnv pointer, a jobject pointer, and any Java arguments declared by the Java method.

Figure 6: JNI communication model. Java- and Native-sides communicate with JNI.


Figure 6 shows the JNI-based communication model adopted by Android. Android uses the JNI Dynamic Register to link native methods. Different from the AIDL model, the JNI-based communication starts from a registration process. When Android starts running, the AndroidRuntime class uses the startReg() method to start the registration of JNI methods, which will further invoke all JNI registration functions implemented in the native libraries.

The registration functions will register native methods with the corresponding Java class specified by an array of JNINativeMethod structures that contains the Java method name, Java method signature, and pointers to the native function. After the registration process, all the JNINativeMethod (on Native-side) is registered and linked to the corresponding Java method in the Java Virtual Machine (JVM).

We further explain the JNI-based communication mechanism with an example given in Figure 7, which is derived from android_hardware_Radio.cpp in AOSP 8.0. The method register_android_hardware_Radio() (line 13) is called to register the JNI methods for Radio, with the JNI method information provided in line 16. Specifically, the kRadioModuleClassPathName variable (line 5) declares the containing class name of the Java method, and gModuleMethods (line 7) declares the correspondence between the Java method and the C++ function. The variable gModuleMethods is defined to contain groups of the Java method name (line 8), parameter and returned types (lines 9 to 10), and the pointer of C++ method (line 11). All the information will be dynamically registered in JVM during run-time. Finally, the C++ method involved in the crosslanguage communication is declared in line 12, while the involving Java method can be found in the java file in package (lines 2 to 3).

Figure 7: An example of JNI-based cross-language communication. The code snippets are simplified for better illustration.


According to the JNI-based communication mechanism, we extract pairs of entry-points from Java- and Native-sides. Specifically, the JNI methods and the corresponding native methods are vaguely identified by a linear sweep searching of keyword RegisterMethodsOrDie, registerNativeMethods and jniRegister NativeMethods over the .cpp files at first. Then we extract the class path name (e.g., the kRadioModuleClassPathName in Figure 7) and the array of JNINativeMethod structures, from which a pair of entry-points can be located and recognized (e.g., the pair of native_setup() and android_hardware_Radio_setup()).

3.3 Cross-Language Protection Mapping Extraction

After the entry-points on both Java- and Native-sides are identified, we further extract the protection mappings from AOSPs. In this section, we first introduce how NatiDroid generates CFG from both sides. Based on the CFG, NatiDroid then traverses the crosslanguage Android API call paths and corresponding security checks (e.g., permission checks) to generate the API-permission protection mappings.

3.3.1 Cross-language CFG Generation. We elaborate the detailed steps involved in generating cross-language CFGs. After obtaining the entry-point pairs from both Java- and Native-sides (as detailed in Section 3.2), NatiDroid first leverages a forward analysis to generate a CFG on the Native-side from each identified native entry-point. If the native-side CFG does not contain any security checkpoint (e.g., permission check, UID check, and PID check), we discard the CFG for computational efficiency. Otherwise, NatiDroid further utilizes a backward analysis to build a Java-side CFG starting from the paired Java-side entry-point to an Android API. If the reached Android API is further invoked by other Android APIs, we extend the CFG until the API is not called by any other APIs. The CFGs generated from both sides are then connected with the communication models identified in Section 3.2. We detail the mechanisms unique to Android that require additional work to handle as follows.

Handling the service identifier. The aforementioned AIDL is of ten used to invoke remote methods in service. Before the invocation, the service is usually pointed by passing a string to the getService or checkService method, for example, the string “media.player” in line 19 of Figure 8. When building the call graph, we need to handle such remote invocation and identify which class is the identifier string actually pointed to. These services are registered to the system through an addService method (either on Java-side or Native-side). Therefore, we can automatically collect the corre spondences between these identifiers and service classes from it. First, we scan the Java and C++ files looking for addService meth ods. Then the program confirms whether the method is ServiceManager.addService or defaultServiceManager->addService, separately. Once confirmed, the program extracts a pair of service class and the corresponding identifier from the parameters; for example, the string identifier “media.player” in Figure 8 will be paired with its service class MediaPlayerService.

Handling Android strong pointer. Although the strong pointer defines the type variable, the type is not necessary to be restricted. Therefore, we need additional efforts to get what type the strong pointer actually points to from the context. According to the strong pointer mechanism, when we find that a member function is called, if the object is declared as a strong pointer, the invocation of the member function will be determined automatically. The NatiDroid will first trace the statement where an object is assigned to the strong pointer. If it is assigned through method getService(), the type of the object will be determined by the passed service identifier; otherwise, NatiDroid will determine the type of strong pointer according to the variable type returned by the function.

Handling member variables. A class member variable is also possibly assigned by a strong pointer. For example, in line 7 of Figure 8, the setAudioSource() method of the mMediaRecorder object is invoked, but from this line of code we cannot determine the type of variable mMediaRecorder so that we cannot determine which setAudioSource() method has been invoked. By looking up in the referenced header file (from line 23), we find that this variable is a member variable of class MediaRecorder. Therefore, to find out the type of this variable, we can search the entire class looking for the assignment or initialization statement. Note that the assignment should be ignored if the assignment releases the pointer, e.g., pointing the variable to a null pointer. In this case, the variable mMediaRecorder is initialized as the return value of createMediaRecorder in the class constructor (line 12). We have explained how to determine the return type of createMediaRecorder in the previous paragraph, handling Android strong pointers. To implement the process automatically, if a variable cannot be tracked in the local scope, NatiDroid will point to the header file to check whether it is a member variable, and thus the tracking scope will be expanded to the entire class.

Handling particular access control. Binder transaction executes with the identity (i.e., PID and UID) of a caller. If a transaction needs to run with callee’s identity, Binder.clearCallingIdentity() can temporarily clear the caller’s identity, so that the callee’s identity will be checked during the transaction. Then the caller’s identity can be restored by Binder.restoreCallingIdentity(). To handle such intervened access control, NatiDroid uses callee’s identity for security control for all methods between the two Binder methods.

3.3.2 Protection Mapping Extraction. We present the workflow of extracting the protection mapping of Android APIs. After obtaining the cross-language CFG, we resort to a Depth-First Search (DFS) strategy to check if there are call paths between Android APIs in the Java API Framework layer and security checks in the Native Library layer. For each node in the CFG, if it is a Java node, we will collect all its native children and obtain the security checks defined in its children nodes. If there are more than one checkpoint on the call trace (e.g., an Android API is protected by multiple permissions),

we concatenate them with AND operation. As inspired by Aafer et al. [9], we also include security checks other than permission enforcement, such as UID and PID checks. If there is more than one Android API along the track, we create a mapping entry for each of them (i.e., all Android APIs along the track have the same security check). Finally, each pair of Java API node and its corresponding security check(s) in Native-side will be added into the protection mapping.


The main contribution of this work, NatiDroid, is to enable the cross-language static analysis of the Android framework. Since there is a number of existing tools [4, 37] and works [9, 13] well handling the static analysis of the Java-side of Android framework, NatiDroid specifically focuses on the analysis of the crosslanguage part of the Android framework. In this section, we run experiments to verify the performance of NatiDroid and to answer

the following research questions:

• RQ1: How effective is NatiDroid in identifying permission enforcement in Native libraries?

• RQ2: How many permission mappings can our tool identify that are not recognized by the state-of-the-practice approaches?

• RQ3: How can our tool contribute to real-world security evaluation?

We use NatiDroid to extract the API protection mapping for 5 AOSP versions – 7.0, 7.1, 8.0, 8.1, and 10.0. We obtained the source code from the official AOSP repository [7]. The experiment ran on a Linux server with Intel (R) Core (TM) i9-9920X CPU @ 3.50GHz and 128 GB RAM.

4.1 RQ1: The Performance of NatiDroid

We present the statics of Permission-API protection mapping extracted from the Native libraries in Table 1 (columns 1 to 6). In each of AOSP 7.0, 7.1, 8.0, and 8.1, our tool identified more than 440 APIs whose permission enforcement take place in the Native code, while in AOSP 10.0, NatiDroid detected 282 APIs containing permission enforcement on the Native side. In Table 2, we list the permissions that have permission checks in native libraries, including 2 dangerous permissions, 8 signature permissions, and 2 normal permissions. Signature permissions are only granted if the requesting app is signed with the same certificate as the app that declared the permission. Normal permissions refer to the permissions with minimal risk to the system and the users’ private data. Dangerous permissions are those higher-risk permissions that would give access to private user data or control over the device that can negatively impact the users.

Due to the lack of ground truth for the permission protection mappings, it is difficult to evaluate the overall accuracy of the extracted mappings. We therefore resort to a manual process to examine the correctness of our mappings. To this end, we manually inspect the involved source code in the AOSP codebase to confirm if the APIs will go through the corresponding security check(s) and if the condition(s) in the security check(s) is(are) consistent with the condition(s) in the mappings. we randomly selected 20% of the total mappings (i.e., 421 mappings) for manual inspection and found no missing or redundant protection conditions in our mappings.

We further looked into the results on the affected API in each AOSP. In AOSP 10.0, the number of affected APIs decreased significantly, compared to other versions (282 in AOSP 10.0 vs. 456*.5 ± 7.*5 in AOSP 7.1 to 8.1). Through the manual code review, we found that two signature permissions, ACCESS_DRM_CERTIFICATES and CONTROL_WIFI_DISPLAY, have been removed in AOSP 10.0. At the same time, the code related to the audio service was refactored and simplified, which greatly reduced the number of exposed methods.

Answer to RQ1. NatiDroid identified more than 440 APIs that are protected by permission enforcement in the Native code in AOSP 7.1-8.1, and 282 APIs in AOSP 10.0, which are verified by manual inspection (20% sampling).

4.2 RQ2: Comparison with other mappings

State-of-the-art works use static and dynamic analysis approaches to extract the API-permission protection mapping from the Android framework. For instance, Axplorer [13] and Arcade [9] use static methods to retrieve the protection mapping. Dynamo [14], on the other hand, extracts the mapping by leveraging dynamic analysis.

This RQ compares our results with the mappings derived from these approaches. Unfortunately, the mapping from Dynamo lacks method signature information (e.g., class name, return type, and parameter list), which is required to identify a method (e.g., there could be methods with identical names in different classes). We cannot accurately compare our mapping with Dynamo’s mapping.

Therefore, in this RQ, we compare our work with Axplorer and Arcade. The mappings of Axplorer and Arcade are derived from their public repositories3 Note that since both works only released their mapping results (for AOSP version 7.1 and under) in lieu of the tools, we are unable to obtain the mappings on AOSP 8.0, 8.1, and 10.0. Table 1 presents the comparison of permission-API protection mappings on the five AOSP versions. Unsurprisingly, sinceNatiDroid only focuses on the permission checks in the Android Native libraries, while Axplorer and Arcade only work on the Android Java framework, there is no overlap between NatiDroid and the two works, respectively. As shown in the first two columns of Table 1, the number of newly identified permissions that are missed in previous works ranges from 9 to 12 in the five AOSP versions. There are 282 to 464 Android APIs associated with these permissions (i.e., invoking these APIs requires the corresponding permissions to be granted), counting up to approximate 30% of the mappings reported in the previous study, which are overlooked in the previous work that only analyzed the Java-side of the Android framework. Table 1 reports the breakdown of the mappings based on the permission protection levels. The mapping results contain the permissions in signature, dangerous, and normal levels. Missing these mappings, especially the ones for the dangerous permissions, will lead to false results in detecting security issues of Android apps, such as permission over-privilege (detailed in Section 4.3). Thus, the main security and privacy threats to the majority of Android apps (i.e., thirdparty apps, which usually have no access to signature permissions) are caused by inaccurate mapping of dangerous permissions. It is therefore worth highlighting that NatiDroid has identified the mappings for two additional dangerous permissions CAMERA and RECORD_AUDIO, which are closely related to user’s privacy.

Answer to RQ2. NatiDroid is able to identify 2 dangerous permission, 8 signature permissions, and 2 normal permissions that previous works have missed. Approximate 30% of the mappings reported in the previous study are related to these permissions.

4.3 RQ3: Applications of Protection Mappings

The protection mappings can be leveraged to detect security issues of Android apps, such as permission over-privilege. In this subsection, we evaluate the effectiveness of our extracted mappings in identifying the security vulnerabilities.

We include two categories of Android apps in our experiments: the custom ROM apps that are pre-installed on the devices, such as Camera and Calendar, as well as the third-party apps that users can download from official or alternative app stores (e.g., social networking apps, banking apps). The experimental dataset contains 1,035 custom ROM apps extracted from five Android custom ROMs of four vendors (i.e., Samsung, LG, Huawei, and Xiaomi) and 10,000 third-party apps randomly downloaded from the Google Play store.

Table 3 shows an overview of the dataset in use. We use the permission protection mappings extracted from AOSP to detect security vulnerabilities in both the custom ROM apps and third-party apps. The AOSP mapping may miss some vendorcustomized permissions (e.g., huawei.permission.SET_SMSC_ADDRESS), which may be used in the custom ROM apps. Nevertheless, we argue that using the AOSP mapping may miss some vulnerabilities caused by the misuse of vendor-customized permissions but will not affect the results corresponding to the official permissions, serving as the main scope of our study.

Permission Over-privilege Detection. Android app developers access Android framework functionalities by invoking Android APIs. Some APIs have access to sensitive information, such as reading the contact list, are protected by permissions. Developers need to request such permissions from the Android system before accessing the sensitive resources. Specifically, a list of required permissions need to be declared in the AndroidManifest.xml file, and the corresponding permissions protected APIs are to be invoked in the app’s implementation.

Figure 9: False-positive over-privileged permissions in previous works detected by NatiDroid.


According to the Android developers’ documentation [5], app developers should request a minimum set of permissions required to complete the app’s functionality, as introducing additional permissions will increase the risk of privacy leak. However, developers usually (either intentionally or unintentionally) request permissions that are not related to the functionalities actually implemented in the app, and hence, not necessary [17]. To detect apps with the permission over-privilege issue, we extract the reachable APIs of the app (with a 30-min timeout), and retrieve its protection conditions (e.g., permission, UID, PID) according to the mappings. For instance, when invoking an Android API, it may check the UID (e.g., uid == AID_SYSTEM checks if the app has system privilege) and the PID (e.g., callingPid == getpid() examines if the method is called by its own process) along with permission enforcement. While the UID can be retrieved statically, the PID has to be determined at run-time, thereby cannot be obtained through static analysis. Nevertheless, the apps included in the experiment are custom ROM apps and third-party apps, which cannot possess PID of Android system services. Therefore, it is safe to assume that callingPid == getpid() will always return false in our tested apps. Finally, if the app declares permission (in the AndroidManifest.xml file) that is not required (i.e., no APIs associated with the permissions found in the app), we flag it as an over-privilege case. Results. Table 4 presents the over-privilege detection results.

To demonstrate the effectiveness of our mappings in pinpointing the permission over-privilege issue, we compare previous works’ results with our results. Recall that NatiDroid only extracts protection mappings from the Native libraries, in our results (i.e., Nati + Ar and Nati + Ax), the Java-side mappings are derived from Arcade and Axplorer. We identify 95.8% and 95.5% apps with a permission over-privilege issue using Arcade’s and Axplorer’s mappings, respectively. Among their results, we identify that 66.6% and 54.2% apps (in Arcade’s and Axplorer’s results, respectively) contain false-positive results caused by missing Native-triggered permission mappings. Specifically, as shown in the last four columns of Table 4, there are 8,063 and 357 permissions that are erroneously identified as over-privilege by Axplorer in 71.5% third-party apps and 22.2% custom ROM apps, respectively; for Axplorer, 7,894 permissions in 71.38% third-party apps and 309 permissions in 21.02% custom ROM apps are found to be false-positive. Interestingly, both Arcade and Axplorer report that a significantly high proportion of apps (approximately 96%) suffer from a permission over-privilege issue. We therefore take an in-depth look into their detection results and observe that the majority of their false positives are caused by missing native triggered INTERNET permission mappings. As illustrated in Figure 9, we further present the breakdown of permissions that cause the false positive results in the comparing methods.

Specifically, missing INTERNET permission mappings leads to 6,661 and 6,660 false positives in Arcade’s and Axplorer’s results. Other missing permission mappings that contribute to the false positives include RECORD_AUDIO (623 false positives in both Arcade and Axplorer), MODIFY_AUDIO_- SETTINGS (424 and 256 false positives in Arcade and Axplorer, respectively), and CAMERA (355 false positives in both Arcade and Axplorer).

Manual inspection. Due to the lack of ground truth, we manually inspect if the over-privileged permissions detected are indeed unneeded by the containing apps. The first two authors of this paper and three security researchers are involved in the manual inspection. The result is determined via majority voting. For each app, we decompile the APK file and locate the relevant APIs. Then, we manually check the app’s context and determine whether the invocation of the APIs meet the conditions in the protection mappings. As this process involves immense manual efforts, it cannot scale to cover a large number of apps. Hence, we manually verified 100 randomly selected apps. Our manual analysis indicates that most of the cases are true positives (95%). The remaining five apps contain implicit parameters passed to the APIs to be examined,which cannot be precisely inferred via static analysis. Nevertheless, we resort to a dynamic approach to verify the remaining five apps. Specifically, we remove the permissions in question from the AndroidManifest.xml file and repackage the app. Then, we manually test the app on an emulator to confirm if the app crashes or the corresponding functions are disabled. As a result, the removal of the permissions in question has no impact on the apps, suggesting that these permissions are indeed unneeded.

Answer to RQ3. Our tool identified that more than half of the over-privilege results from state-of-the-practice tools are false-positives, which is caused by missing Native-triggered permission mappings.

5 THREATS TO VALIDITY Android versions. In this paper, we propose a solution to facilitate cross-language static analysis of the Android framework andbuild a prototype system, NatiDroid, to extract API-permission mapping from the Android operating system. To compare with the state-of-the-practice works Axplorer and Arcade, which are close sourced and only generated the mappings up to Android 7.1, in our experiment, we extract the mappings from the latest versions they have (i.e., 7.0 and 7.1) and three newer versions (i.e., 8.0, 8.1 and 10.0). Nevertheless, the proposed solution can apply to any Android version, with further engineering works to be done in the pre-processing module. Custom ROMs. Android smartphones such as Samsung, Huawei and Xiaomi, are shipped with vendor-customized Android systems (i.e., custom ROMs) rather than the AOSP. Unfortunately, these custom ROMs are not open-source. The proposed solution takes the source code as input; therefore, it cannot extract permission mappings from these close sourced custom ROMs. However, smartphone vendors can use our solution to analyze their customized Android versions based on their source code. Nevertheless, to maintain the compatibility of running third-party apps, such custom ROMs are not likely to modify the normal and dangerous level permission specifications of AOSP that third-party apps can access, but rather add a few signature level permissions for their own system apps. Therefore, the results derived from AOSP will not affect the security analysis of third-party apps, which are the majority in the Android ecosystem. On the other hand, with NatiDroid, thirdparty vendors can perform an inner security analysis on custom ROM source code, determine whether there are errors in the implementation of permission mappings, and further detect permission over-privilege before releasing an app. Static analysis. When detecting over-privilege issues in Android apps, we may suffer from the intrinsic vulnerability of static code analysis when encountering code obfuscation and reflection, which may lead to the unsoundness of our results. When building the apps’ call graph, our method may yield unsound results because it may miss the context and the parameters that can only be obtained at run-time. For example, the API void setDataSource requires the Internet permission when the data source is online media. The source is not always a static string so that it may be assigned at run-time. Nevertheless, these challenges are regarded as well known and non-trivial issues to overcome in the research community [34].


Chaoran citation, surname not first name Android API protection mapping. Stowaway [17] initially explored and analyzed the Android permission specification.

They extracted API mappings based on the feedback directed fuzz testing, and dynamically recorded the permission checks of APIs. The mappings they extracted are accurate, but the code coverage is limited. To address the limitations of low code coverage, PScout [12] uses static analysis to extract the API protection mapping. However, they did not consider the context of the API invocation, and thus may produce false positive mappings. Axplorer [13] leverages more accurate static analysis on the SDK and Android framework, and generates more precise permission specifications. Arcade [9] conducted a similar static analysis, with additional attention paid to extract other security mechanisms, such as UID and PID checks. While these works only analyzed the Java-side of the Android, none of the works has looked into the native libraries within the Android framework. In order to overcome the limitations of static analysis, Dynamo [14] uses dynamic analysis, aiming to obtain more accurate mapping. PSGen [39] conducts an analysis permission specification for Android NDK (i.e., both protected APIs and permission checks are in the Native code), which has a different scope to our approach (i.e., protected APIs are in the Java framework, while the permission checks are in the Native code).

Our work fills the research gap by analyzing the native libraries and their communications with the Java framework to produce more comprehensive permission protection mappings. Cross-language analysis on Android. Chaoran NCScope: hardwareassisted analyzer for native code in Android apps A plethora of works have proposed to solve the analysis of cross-language code. George et al. [20] scanned the binary libraries and cross-referenced the information to search the call-backs from Native code to Java. Their work focuses on the JNI mechanism alone. However, the Android framework provides other IPC mechanisms, such as AIDL, which are not considered. Fengguo et al. [38] proposed a static analysis framework that focuses on performing cross-language modeling and generating call graphs for the analyzed apps. Jucify [36] conducts a static analysis approach which extends the app analysis to native codes. Nevertheless, these works are only applicable to Android apps, which are far less complicated than the Android framework we analyzed. In addition, our cross-language analysis handles various Android IPC mechanisms such as JNI and AIDL.


We proposed a novel approach, NatiDroid, to facilitate the crosslanguage analysis of the Android framework. NatiDroid identifies the entry-point pairs of both Java- and Native-sides of the Android framework, where both sides are communicated through JNI and AIDL based mechanisms, so NatiDroid builds the cross-language CFG on the overall Android framework (Java + Native code). Based on the cross-language CFG, we extracted Native-triggered permission specifications and created the protection mappings in the native code to complement existing Java-based mappings. We further applied our new mappings to detect permission over-privilege vulnerabilities in a large dataset consisting of more than 11,000 Android apps. We finally show that using the mapping derived by NatiDroid can identify a significant number of false results existing in the state of the art, such as Axplorer and Arcade.


[1] 1999. Soot - Java Analysis Framework.

[2] 2000. Clang: A C language family frontend for LLVM.

[3] 2000. Introduction to the Clang AST.


[4] 2006. WALA: T.J. Watson Libraries for Analysis.

[5] 2008. Developer Guides | Android Developers.


[6] 2012. Soong Build System.

[7] 2021. Android Open Source Project.

[8] 2021. Google Play - Camera360 Photo Editor + Camera & Beauty Selfies. https:


[9] Yousra Aafer, Guanhong Tao, Jianjun Huang, Xiangyu Zhang, and Ninghui Li.

2018. Precise Android API protection mapping derivation and reasoning. In

Proceedings of the 2018 ACM SIGSAC Conference on Computer and Communications

Security. 1151–1164.

[10] Yousra Aafer, Nan Zhang, Zhongwen Zhang, Xiao Zhang, Kai Chen, XiaoFeng

Wang, Xiaoyong Zhou, Wenliang Du, and Michael Grace. 2015. Hare hunting in

the wild Android: A study on the threat of hanging attribute references. In Proceedings of the 22nd ACM SIGSAC Conference on Computer and Communications

Security. 1248–1259.

[11] Steven Arzt, Siegfried Rasthofer, Christian Fritz, Eric Bodden, Alexandre Bartel, Jacques Klein, Yves Le Traon, Damien Octeau, and Patrick McDaniel. 2014.

Flowdroid: Precise context, flow, field, object-sensitive and lifecycle-aware taint

analysis for Android apps. ACM SIGPLAN Notices 49, 6 (2014), 259–269.

[12] Kathy Wain Yee Au, Yi Fan Zhou, Zhen Huang, and David Lie. 2012. Pscout:

analyzing the Android permission specification. In Proceedings of the 2012 ACM

conference on Computer and Communications Security. 217–228.

[13] Michael Backes, Sven Bugiel, Erik Derr, Patrick McDaniel, Damien Octeau, and

Sebastian Weisgerber. 2016. On Demystifying the Android Application Framework: Re-Visiting Android Permission Specification Analysis. In 25th USENIX

Security Symposium (USENIX Security 16). USENIX Association, Austin, TX,


[14] Abdallah Dawoud and Sven Bugiel. 2021. Bringing balance to the force: Dynamic

analysis of the android application framework. In NDSS.

[15] Manuel Egele, David Brumley, Yanick Fratantonio, and Christopher Kruegel.

2013. An empirical study of cryptographic misuse in android applications. In

Proceedings of the 2013 ACM SIGSAC conference on Computer & communications

security. 73–84.

[16] Sascha Fahl, Marian Harbach, Marten Oltrogge, Thomas Muders, and Matthew

Smith. 2013. Hey, you, get off of my clipboard. In International Conference on

Financial Cryptography and Data Security. Springer, 144–161.

[17] Adrienne Porter Felt, Erika Chin, Steve Hanna, Dawn Song, and David Wagner.

2011. Android permissions demystified. In Proceedings of the 18th ACM conference

on Computer and Communications Security. 627–638.

[18] Yu Feng, Saswat Anand, Isil Dillig, and Alex Aiken. 2014. Apposcopy: Semanticsbased detection of Android malware through static analysis. In Proceedings of

the 22nd ACM SIGSOFT International Symposium on Foundations of Software

Engineering. 576–587.

[19] Earlence Fernandes, Jaeyeon Jung, and Atul Prakash. 2016. Security analysis

of emerging smart home applications. In 2016 IEEE symposium on security and

privacy (SP). IEEE, 636–654.

[20] George Fourtounis, Leonidas Triantafyllou, and Yannis Smaragdakis. 2020. Identifying Java calls in native code via binary scanning. In Proceedings of the 29th ACM

SIGSOFT International Symposium on Software Testing and Analysis. 388–400.

[21] Clint Gibler, Jonathan Crussell, Jeremy Erickson, and Hao Chen. 2012. AndroidLeaks: automatically detecting potential privacy leaks in Android applications

on a large scale. In International Conference on Trust and Trustworthy Computing.

Springer, 291–307.

[22] Michael I Gordon, Deokhwan Kim, Jeff H Perkins, Limei Gilham, Nguyen Nguyen,

and Martin C Rinard. 2015. Information flow analysis of Android applications in

DroidSafe. In NDSS, Vol. 15. 110.

[23] Michael C Grace, Yajin Zhou, Zhi Wang, and Xuxian Jiang. 2012. Systematic

detection of capability leaks in stock Android smartphones. In NDSS, Vol. 14. 19.

[24] Jianjun Huang, Xiangyu Zhang, and Lin Tan. 2016. Detecting sensitive data disclosure via bi-directional text correlation analysis. In Proceedings of the 2016 24th

ACM SIGSOFT International Symposium on Foundations of Software Engineering.


[25] Soo Hyeon Kim, Daewan Han, and Dong Hoon Lee. 2013. Predictability of

android OpenSSL’s pseudo random number generator. In Proceedings of the 2013

ACM SIGSAC conference on Computer & Communications Security. 659–668.

[26] William Klieber, Lori Flynn, Amar Bhosale, Limin Jia, and Lujo Bauer. 2014.

Android taint flow analysis for app sets. In Proceedings of the 3rd ACM SIGPLAN

International Workshop on the State of the Art in Java Program Analysis. 1–6.

[27] Li Li, Alexandre Bartel, Jacques Klein, Yves Le Traon, Steven Arzt, Siegfried

Rasthofer, Eric Bodden, Damien Octeau, and Patrick Mcdaniel. 2014. I know

what leaked in your pocket: Uncovering privacy leaks on Android Apps with

Static Taint Analysis. arXiv preprint arXiv:1404.7431 (2014).

[28] Tongxin Li, Xiaoyong Zhou, Luyi Xing, Yeonjoon Lee, Muhammad Naveed, XiaoFeng Wang, and Xinhui Han. 2014. Mayhem in the push clouds: Understanding

and mitigating security hazards in mobile push-messaging services. In Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications

Security. 978–989.

[29] Baozheng Liu, Chao Zhang, Guang Gong, Yishun Zeng, Haifeng Ruan, and

Jianwei Zhuge. 2020. FANS: Fuzzing Android Native System Services via Automated Interface Analysis. In 29th USENIX Security Symposium (USENIX Security 20). USENIX Association, 307–323.


[30] Kangjie Lu, Zhichun Li, Vasileios P Kemerlis, Zhenyu Wu, Long Lu, Cong Zheng,

Zhiyun Qian, Wenke Lee, and Guofei Jiang. 2015. Checking more and alerting

less: Detecting privacy leakages via enhanced data-flow analysis and peer voting.


[31] Mohammad Nauman, Sohail Khan, and Xinwen Zhang. 2010. Apex: Extending

Android permission model and enforcement with user-defined runtime constraints. In Proceedings of the 5th ACM symposium on Information, Computer and

Communications Security. 328–332.

[32] Damien Octeau, Patrick McDaniel, Somesh Jha, Alexandre Bartel, Eric Bodden, Jacques Klein, and Yves Le Traon. 2013. Effective Inter-Component Communication Mapping in Android: An Essential Step Towards Holistic Security

Analysis. In 22nd USENIX Security Symposium (USENIX Security 13). USENIX

Association, Washington, D.C., 543–558.


[33] Rahul Pandita, Xusheng Xiao, Wei Yang, William Enck, and Tao Xie. 2013. WHYPER: Towards Automating Risk Assessment of Mobile Applications. In 22nd

USENIX Security Symposium (USENIX Security 13). USENIX Association, Washington, D.C., 527–542.


[34] Felix Pauck, Eric Bodden, and Heike Wehrheim. 2018. Do android taint analysis

tools keep their promises?. In Proceedings of the 2018 26th ACM Joint Meeting on

European Software Engineering Conference and Symposium on the Foundations of

Software Engineering. 331–341.

[35] Zhengyang Qu, Vaibhav Rastogi, Xinyi Zhang, Yan Chen, Tiantian Zhu, and

Zhong Chen. 2014. Autocog: Measuring the description-to-permission fidelity

in Android applications. In Proceedings of the 2014 ACM SIGSAC Conference on

Computer and Communications Security. 1354–1365.

[36] Jordan Samhi, Jun Gao, Nadia Daoudi, Pierre Graux, Henri Hoyez, Xiaoyu Sun,

Kevin Allix, and Bissyandé. 2022. JuCify: A Step Towards Android Code Unification for Enhanced Static Analysis. In 2022 IEEE/ACM 44th International Conference

on Software Engineering (ICSE).

[37] Raja Vallée-Rai, Phong Co, Etienne Gagnon, Laurie Hendren, Patrick Lam, and

Vijay Sundaresan. 2010. Soot: A Java bytecode optimization framework. In

CASCON First Decade High Impact Papers. 214–224.

[38] Fengguo Wei, Sankardas Roy, and Xinming Ou. 2018. Amandroid: A precise and

general inter-component data flow analysis framework for security vetting of

Android apps. ACM Transactions on Privacy and Security (TOPS) 21, 3 (2018),


[39] Hao Zhou, Haoyu Wang, Shuohan Wu, Xiapu Luo, Yajin Zhou, Ting Chen, and

Ting Wang. 2021. Finding the Missing Piece: Permission Specification Analysis

for Android NDK. In 2021 36th IEEE/ACM International Conference on Automated

Software Engineering (ASE). IEEE, 505–516.

Subscribe to HyperLab
Receive the latest updates directly to your inbox.
This entry has been permanently stored onchain and signed by its creator.
More from HyperLab