Documentation and examples

This commit is contained in:
Ed Minnix
2023-03-02 10:37:44 -05:00
parent d3d712fbff
commit fa416564c7
4 changed files with 150 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
Android allows an application to install an APK (Android package kit)
using an <code>Intent</code> with
the <code>"application/vnd.android.package-archive"</code> MIME type. If
the file used in the <code>Intent</code> is from a location that is not
controlled by the application (for example, the SD card which is
universally writable), this can result in the installation of an
application which was not intended.
</p>
</overview>
<recommendation>
<p>
It is advised to transition to install packages using
the <code>PackageInstaller</code> class.
</p>
<p>
If installation from a file is necessary, it is best to use
a <code>FileProvider</code>. Content providers can provide more specific
permissions than file system permissions can.
</p>
<p>
When your application does not require installing packages, do not add
the <code>REQUEST_INSTALL_PACKAGES</code> permission in the manifest file.
</p>
</recommendation>
<example>
<p>
In the following (bad) example, the package is installed from a file which
may be altered by another application.
</p>
<sample src="InstallApkWithFile.java"/>
<p>
In the following (good) example, the package is installed by using
a <code>FileProvider</code>.
</p>
<sample src="InstallApkWithFileProvider.java"/>
<p>
In the following (good) example, the package is installed using an
instance of the <code>android.content.pm.PackageInstaller</code> class.
</p>
<sample src="InstallApkWithPackageInstaller.java"/>
</example>
<references>
<li>
Intent.ACTION_INSTALL_PACKAGE: <a href="https://developer.android.com/reference/android/content/Intent#ACTION_INSTALL_PACKAGE"></a>.
</li>
<li>
Android Manifest Permission to Install Packages: <a href="https://developer.android.com/reference/android/Manifest.permission#REQUEST_INSTALL_PACKAGES"></a>.
</li>
<li>
PackageInstaller: <a href="https://developer.android.com/reference/android/content/pm/PackageInstaller"></a>.
</li>
<li>
FileProvider: <a href="https://developer.android.com/reference/androidx/core/content/FileProvider"></a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,14 @@
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import java.io.File;
/* Get a file from external storage */
File file = new File(Environment.getExternalStorageDirectory(), "myapp.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
/* Set the mimetype to APK */
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);

View File

@@ -0,0 +1,31 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
String tempFilename = "temporary.apk";
byte[] buffer = new byte[16384];
/* Copy application asset into temporary file */
try (InputStream is = getAssets().open(assetName);
FileOutputStream fout = openFileOutput(tempFilename, Context.MODE_PRIVATE)) {
int n;
while ((n=is.read(buffer)) >= 0) {
fout.write(buffer, 0, n);
}
}
/* Expose temporary file with FileProvider */
File toInstall = new File(this.getFilesDir(), tempFilename);
Uri applicationUri = FileProvider.getUriForFile(this, "com.example.apkprovider", toInstall);
/* Create Intent and set data to APK file. */
Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(applicationUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

View File

@@ -0,0 +1,32 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
private static final String PACKAGE_INSTALLED_ACTION =
"com.example.SESSION_API_PACKAGE_INSTALLED";
/* Create the package installer and session */
PackageInstaller packageInstaller = getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params =
new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
/* Load asset into session */
try (OutputStream packageInSession = session.openWrite("package", 0, -1);
InputStream is = getAssets().open(assetName)) {
byte[] buffer = new byte[16384];
int n;
while ((n = is.read(buffer)) >= 0) {
packageInSession.write(buffer, 0, n);
}
}
/* Create status receiver */
Intent intent = new Intent(this, InstallApkSessionApi.class);
intent.setAction(PACKAGE_INSTALLED_ACTION);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
IntentSender statusReceiver = pendingIntent.getIntentSender();
/* Commit the session */
session.commit(statusReceiver);