Skip to content

Commit 821d8c9

Browse files
authored
Merge pull request #1436 from yh-semmle/java-android-manifest
Approved by aschackmull
2 parents d14d31c + 8e6b62a commit 821d8c9

File tree

6 files changed

+287
-0
lines changed

6 files changed

+287
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Provides classes and predicates for working with Android components.
3+
*/
4+
5+
import java
6+
import semmle.code.xml.AndroidManifest
7+
8+
/**
9+
* An Android component. That is, either an activity, a service,
10+
* a broadcast receiver, or a content provider.
11+
*/
12+
class AndroidComponent extends Class {
13+
AndroidComponent() {
14+
this.getASupertype*().hasQualifiedName("android.app", "Activity") or
15+
this.getASupertype*().hasQualifiedName("android.app", "Service") or
16+
this.getASupertype*().hasQualifiedName("android.content", "BroadcastReceiver") or
17+
this.getASupertype*().hasQualifiedName("android.content", "ContentProvider")
18+
}
19+
20+
/** The XML element corresponding to this Android component. */
21+
AndroidComponentXmlElement getAndroidComponentXmlElement() {
22+
result.getResolvedComponentName() = this.getQualifiedName()
23+
}
24+
25+
/** Holds if this Android component is configured as `exported` in an `AndroidManifest.xml` file. */
26+
predicate isExported() { getAndroidComponentXmlElement().isExported() }
27+
28+
/** Holds if this Android component has an intent filter configured in an `AndroidManifest.xml` file. */
29+
predicate hasIntentFilter() { exists(getAndroidComponentXmlElement().getAnIntentFilterElement()) }
30+
}
31+
32+
/** An Android activity. */
33+
class AndroidActivity extends AndroidComponent {
34+
AndroidActivity() { this.getASupertype*().hasQualifiedName("android.app", "Activity") }
35+
}
36+
37+
/** An Android service. */
38+
class AndroidService extends AndroidComponent {
39+
AndroidService() { this.getASupertype*().hasQualifiedName("android.app", "Service") }
40+
}
41+
42+
/** An Android broadcast receiver. */
43+
class AndroidBroadcastReceiver extends AndroidComponent {
44+
AndroidBroadcastReceiver() {
45+
this.getASupertype*().hasQualifiedName("android.content", "BroadcastReceiver")
46+
}
47+
}
48+
49+
/** An Android content provider. */
50+
class AndroidContentProvider extends AndroidComponent {
51+
AndroidContentProvider() {
52+
this.getASupertype*().hasQualifiedName("android.content", "ContentProvider")
53+
}
54+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
/**
2+
* Provides classes and predicates for working with Android manifest files.
3+
*/
4+
5+
import XML
6+
7+
/**
8+
* An Android manifest file, named `AndroidManifest.xml`.
9+
*/
10+
class AndroidManifestXmlFile extends XMLFile {
11+
AndroidManifestXmlFile() {
12+
this.getBaseName() = "AndroidManifest.xml" and
13+
count(XMLElement e | e = this.getAChild()) = 1 and
14+
this.getAChild().getName() = "manifest"
15+
}
16+
17+
/**
18+
* Gets the top-level `<manifest>` element in this Android manifest file.
19+
*/
20+
AndroidManifestXmlElement getManifestElement() { result = this.getAChild() }
21+
}
22+
23+
/**
24+
* A `<manifest>` element in an Android manifest file.
25+
*/
26+
class AndroidManifestXmlElement extends XMLElement {
27+
AndroidManifestXmlElement() {
28+
this.getParent() instanceof AndroidManifestXmlFile and this.getName() = "manifest"
29+
}
30+
31+
/**
32+
* Gets the `<application>` child element of this `<manifest>` element.
33+
*/
34+
AndroidApplicationXmlElement getApplicationElement() { result = this.getAChild() }
35+
36+
/**
37+
* Gets the value of the `package` attribute of this `<manifest>` element.
38+
*/
39+
string getPackageAttributeValue() { result = getAttributeValue("package") }
40+
}
41+
42+
/**
43+
* An `<application>` element in an Android manifest file.
44+
*/
45+
class AndroidApplicationXmlElement extends XMLElement {
46+
AndroidApplicationXmlElement() {
47+
this.getParent() instanceof AndroidManifestXmlElement and this.getName() = "application"
48+
}
49+
50+
/**
51+
* Gets a component child element of this `<application>` element.
52+
*/
53+
AndroidComponentXmlElement getAComponentElement() { result = this.getAChild() }
54+
}
55+
56+
/**
57+
* An `<activity>` element in an Android manifest file.
58+
*/
59+
class AndroidActivityXmlElement extends AndroidComponentXmlElement {
60+
AndroidActivityXmlElement() { this.getName() = "activity" }
61+
}
62+
63+
/**
64+
* A `<service>` element in an Android manifest file.
65+
*/
66+
class AndroidServiceXmlElement extends AndroidComponentXmlElement {
67+
AndroidServiceXmlElement() { this.getName() = "service" }
68+
}
69+
70+
/**
71+
* A `<receiver>` element in an Android manifest file.
72+
*/
73+
class AndroidReceiverXmlElement extends AndroidComponentXmlElement {
74+
AndroidReceiverXmlElement() { this.getName() = "receiver" }
75+
}
76+
77+
/**
78+
* A `<provider>` element in an Android manifest file.
79+
*/
80+
class AndroidProviderXmlElement extends AndroidComponentXmlElement {
81+
AndroidProviderXmlElement() { this.getName() = "provider" }
82+
}
83+
84+
/**
85+
* An Android component element in an Android manifest file.
86+
*/
87+
class AndroidComponentXmlElement extends XMLElement {
88+
AndroidComponentXmlElement() {
89+
this.getParent() instanceof AndroidApplicationXmlElement and
90+
this.getName().regexpMatch("(activity|service|receiver|provider)")
91+
}
92+
93+
/**
94+
* Gets an `<intent-filter>` child element of this component element.
95+
*/
96+
AndroidIntentFilterXmlElement getAnIntentFilterElement() { result = this.getAChild() }
97+
98+
/**
99+
* Gets the value of the `android:name` attribute of this component element.
100+
*/
101+
string getComponentName() {
102+
exists(XMLAttribute attr |
103+
attr = getAnAttribute() and
104+
attr.getNamespace().getPrefix() = "android" and
105+
attr.getName() = "name"
106+
|
107+
result = attr.getValue()
108+
)
109+
}
110+
111+
/**
112+
* Gets the resolved value of the `android:name` attribute of this component element.
113+
*/
114+
string getResolvedComponentName() {
115+
if getComponentName().matches(".%")
116+
then
117+
result = getParent()
118+
.(XMLElement)
119+
.getParent()
120+
.(AndroidManifestXmlElement)
121+
.getPackageAttributeValue() + getComponentName()
122+
else result = getComponentName()
123+
}
124+
125+
/**
126+
* Gets the value of the `android:exported` attribute of this component element.
127+
*/
128+
string getExportedAttributeValue() {
129+
exists(XMLAttribute attr |
130+
attr = getAnAttribute() and
131+
attr.getNamespace().getPrefix() = "android" and
132+
attr.getName() = "exported"
133+
|
134+
result = attr.getValue()
135+
)
136+
}
137+
138+
/**
139+
* Holds if the `android:exported` attribute of this component element is `true`.
140+
*/
141+
predicate isExported() { getExportedAttributeValue() = "true" }
142+
}
143+
144+
/**
145+
* An `<intent-filter>` element in an Android manifest file.
146+
*/
147+
class AndroidIntentFilterXmlElement extends XMLElement {
148+
AndroidIntentFilterXmlElement() {
149+
this.getFile() instanceof AndroidManifestXmlFile and this.getName() = "intent-filter"
150+
}
151+
152+
/**
153+
* Gets an `<action>` child element of this `<intent-filter>` element.
154+
*/
155+
AndroidActionXmlElement getAnActionElement() { result = this.getAChild() }
156+
}
157+
158+
/**
159+
* An `<action>` element in an Android manifest file.
160+
*/
161+
class AndroidActionXmlElement extends XMLElement {
162+
AndroidActionXmlElement() {
163+
this.getFile() instanceof AndroidManifestXmlFile and this.getName() = "action"
164+
}
165+
166+
/**
167+
* Gets the name of this action.
168+
*/
169+
string getActionName() {
170+
exists(XMLAttribute attr |
171+
attr = getAnAttribute() and
172+
attr.getNamespace().getPrefix() = "android" and
173+
attr.getName() = "name"
174+
|
175+
result = attr.getValue()
176+
)
177+
}
178+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:versionCode="1"
5+
android:versionName="1.0"
6+
package="com.example.myapp">
7+
8+
<!-- Beware that these values are overridden by the build.gradle file -->
9+
<uses-sdk android:minSdkVersion="15" android:targetSdkVersion="26" />
10+
11+
<application
12+
android:allowBackup="true"
13+
android:icon="@mipmap/ic_launcher"
14+
android:roundIcon="@mipmap/ic_launcher_round"
15+
android:label="@string/app_name"
16+
android:supportsRtl="true"
17+
android:theme="@style/AppTheme">
18+
19+
<!-- This name is resolved to com.example.myapp.MainActivity
20+
based upon the package attribute -->
21+
<activity android:name=".MainActivity">
22+
<intent-filter>
23+
<action android:name="android.intent.action.MAIN" />
24+
<category android:name="android.intent.category.LAUNCHER" />
25+
</intent-filter>
26+
</activity>
27+
28+
<activity
29+
android:name=".DisplayMessageActivity"
30+
android:parentActivityName=".MainActivity" />
31+
</application>
32+
</manifest>
33+
34+
<!--
35+
/*
36+
* This file is licensed under the Apache License, Version 2.0
37+
* (the "License"); you may not use this file except in compliance with
38+
* the License. You may obtain a copy of the License at
39+
*
40+
* http://www.apache.org/licenses/LICENSE-2.0
41+
*
42+
* Unless required by applicable law or agreed to in writing, software
43+
* distributed under the License is distributed on an "AS IS" BASIS,
44+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45+
* See the License for the specific language governing permissions and
46+
* limitations under the License.
47+
*/
48+
-->
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
class Test {}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| com.example.myapp.MainActivity | android.intent.action.MAIN |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java
2+
import semmle.code.xml.AndroidManifest
3+
4+
from AndroidActivityXmlElement e
5+
select e.getResolvedComponentName(), e.getAnIntentFilterElement().getAnActionElement().getActionName()

0 commit comments

Comments
 (0)