How to Check If an App is System App or Not

Definition

The definition of system app is not very clear. There are at least three different definitions:

  1. Apps in system partition (/system)
    • These apps will get the flag ApplicationInfo.FLAG_SYSTEM
    • If an updated version is installed (probably not under /system), it will get ApplicationInfo.FLAG_UPDATED_SYSTEM_APP
  2. Apps signed with platform signature
  3. Apps in /system/priv-apps and /system/framework
    • These apps will get the flag ApplicationInfo.PRIVATE_FLAG_PRIVILEGED
    • The flag is set in PackageManagerService.java
    • These apps will be granted signatureOrSystem level permissions (corresponding to the System in signatureOrSystem)
    • For Samsung, apps in /system/carrier/priv-app and /odm/priv-app will also get this flag

Check

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import java.lang.reflect.*;

public class MainActivity extends AppCompatActivity {

private static final String TAG = "XKXXXX";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);


PackageManager pm = getApplicationContext().getPackageManager();
List<PackageInfo> list = pm.getInstalledPackages(0);
for(PackageInfo pi : list) {
try {
ApplicationInfo ai = pm.getApplicationInfo(pi.packageName, 0);
String strSignedBySys = isSignedBySystem(pm, pi.packageName)?"SYS_SIGN":"NONSYS_SIGN";
String strUnderSys = isAppInSystemPartition(pm, pi.packageName)?"UNDER_SYS":"NOT_UNDER_SYS";
String strPrivileged = isPrivilegedApp(ai)?"PRIV":"NON_PRIV";
Log.d(TAG, String.format(">>>>>> %s <<<<<<<< %s %s %s %s",
pi.packageName,
ai.publicSourceDir,
strSignedBySys,
strUnderSys,
strPrivileged));
}catch (Exception e) {
Log.d(TAG, "exception ", e);
}
}
}

/**
* Check if an App is under /system or has been installed as an update to a built-in system application.
*/
public static boolean isAppInSystemPartition(PackageManager pm, String packageName) {
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
return ((ai.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0);
}catch (NameNotFoundException e) {
Log.d(TAG, "exception", e);
return false;
}
}

/**
* Check if an App is signed by system or not.
*/
public boolean isSignedBySystem(PackageManager pm, String packageName) {
try {
PackageInfo pi_app = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
PackageInfo pi_sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
return (pi_app != null
&& pi_app.signatures != null
&& pi_sys.signatures[0].equals(pi_app.signatures[0]));
}catch (NameNotFoundException e) {
Log.d(TAG, "exception", e);
return false;
}
}

/**
* Check if an App has ApplicationInfo.PRIVATE_FLAG_PRIVILEGED (under /system/priv-app or /system/framework)
*/
public static boolean isPrivilegedApp(ApplicationInfo ai) {
try {
Method method = ApplicationInfo.class.getDeclaredMethod("isPrivilegedApp");
return (Boolean)method.invoke(ai);
} catch(Exception e) {
Log.d(TAG, "exception", e);
return false;
}
}
}

Reference

Definition of PRIVATE_FLAG_PRIVILEGED in ApplicationInfo.java
How to check if application is system app or not (By signed signature)
Android permission element