Skip to content

Commit fa41656

Browse files
committed
Documentation and examples
1 parent d3d712f commit fa41656

File tree

4 files changed

+150
-0
lines changed

4 files changed

+150
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Android allows an application to install an APK (Android package kit)
8+
using an <code>Intent</code> with
9+
the <code>"application/vnd.android.package-archive"</code> MIME type. If
10+
the file used in the <code>Intent</code> is from a location that is not
11+
controlled by the application (for example, the SD card which is
12+
universally writable), this can result in the installation of an
13+
application which was not intended.
14+
</p>
15+
</overview>
16+
17+
<recommendation>
18+
<p>
19+
It is advised to transition to install packages using
20+
the <code>PackageInstaller</code> class.
21+
</p>
22+
23+
<p>
24+
If installation from a file is necessary, it is best to use
25+
a <code>FileProvider</code>. Content providers can provide more specific
26+
permissions than file system permissions can.
27+
</p>
28+
29+
<p>
30+
When your application does not require installing packages, do not add
31+
the <code>REQUEST_INSTALL_PACKAGES</code> permission in the manifest file.
32+
</p>
33+
</recommendation>
34+
35+
<example>
36+
37+
<p>
38+
In the following (bad) example, the package is installed from a file which
39+
may be altered by another application.
40+
</p>
41+
42+
<sample src="InstallApkWithFile.java"/>
43+
44+
<p>
45+
In the following (good) example, the package is installed by using
46+
a <code>FileProvider</code>.
47+
</p>
48+
49+
<sample src="InstallApkWithFileProvider.java"/>
50+
51+
<p>
52+
In the following (good) example, the package is installed using an
53+
instance of the <code>android.content.pm.PackageInstaller</code> class.
54+
</p>
55+
56+
<sample src="InstallApkWithPackageInstaller.java"/>
57+
</example>
58+
59+
<references>
60+
<li>
61+
Intent.ACTION_INSTALL_PACKAGE: <a href="https://developer.android.com/reference/android/content/Intent#ACTION_INSTALL_PACKAGE"></a>.
62+
</li>
63+
<li>
64+
Android Manifest Permission to Install Packages: <a href="https://developer.android.com/reference/android/Manifest.permission#REQUEST_INSTALL_PACKAGES"></a>.
65+
</li>
66+
<li>
67+
PackageInstaller: <a href="https://developer.android.com/reference/android/content/pm/PackageInstaller"></a>.
68+
</li>
69+
<li>
70+
FileProvider: <a href="https://developer.android.com/reference/androidx/core/content/FileProvider"></a>.
71+
</li>
72+
</references>
73+
</qhelp>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import android.app.Activity;
2+
import android.content.Intent;
3+
import android.net.Uri;
4+
import android.os.Environment;
5+
6+
import java.io.File;
7+
8+
/* Get a file from external storage */
9+
File file = new File(Environment.getExternalStorageDirectory(), "myapp.apk");
10+
Intent intent = new Intent(Intent.ACTION_VIEW);
11+
/* Set the mimetype to APK */
12+
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
13+
14+
startActivity(intent);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import android.app.Activity;
2+
import android.content.Context;
3+
import android.content.Intent;
4+
import android.net.Uri;
5+
import androidx.core.content.FileProvider;
6+
7+
import java.io.File;
8+
import java.io.FileOutputStream;
9+
10+
String tempFilename = "temporary.apk";
11+
byte[] buffer = new byte[16384];
12+
13+
/* Copy application asset into temporary file */
14+
try (InputStream is = getAssets().open(assetName);
15+
FileOutputStream fout = openFileOutput(tempFilename, Context.MODE_PRIVATE)) {
16+
int n;
17+
while ((n=is.read(buffer)) >= 0) {
18+
fout.write(buffer, 0, n);
19+
}
20+
}
21+
22+
/* Expose temporary file with FileProvider */
23+
File toInstall = new File(this.getFilesDir(), tempFilename);
24+
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall);
25+
26+
/* Create Intent and set data to APK file. */
27+
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
28+
intent.setData(applicationUri);
29+
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
30+
31+
startActivity(intent);
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import android.content.Context;
2+
import android.content.Intent;
3+
import android.content.pm.PackageInstaller;
4+
5+
private static final String PACKAGE_INSTALLED_ACTION =
6+
"com.example.SESSION_API_PACKAGE_INSTALLED";
7+
8+
/* Create the package installer and session */
9+
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
10+
PackageInstaller.SessionParams params =
11+
new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
12+
int sessionId = packageInstaller.createSession(params);
13+
session = packageInstaller.openSession(sessionId);
14+
15+
/* Load asset into session */
16+
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
17+
InputStream is = getAssets().open(assetName)) {
18+
byte[] buffer = new byte[16384];
19+
int n;
20+
while ((n = is.read(buffer)) >= 0) {
21+
packageInSession.write(buffer, 0, n);
22+
}
23+
}
24+
25+
/* Create status receiver */
26+
Intent intent = new Intent(this, InstallApkSessionApi.class);
27+
intent.setAction(PACKAGE_INSTALLED_ACTION);
28+
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
29+
IntentSender statusReceiver = pendingIntent.getIntentSender();
30+
31+
/* Commit the session */
32+
session.commit(statusReceiver);

0 commit comments

Comments
 (0)