Installing an Android apk programmatically as part of a test framework - android

I'm attempting to install an apk programmatically, but I'm not having much luck. I'm setting up an automated test framework targeting physical devices, and I want to have the test devices retrieve the latest apk from the build server before running tests. While I am aware that there is no general way to actually install an apk without the user's consent, I'm curious if there might be some approach available in the case where a developer owns both the apk and device.
Approaches I've tried in the past (the apk has been downloaded to pathName/apkFilename):
String command = "adb install " + pathName + apkFilename;
Runtime.getRuntime().exec(command);
And:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(pathName + apkFilename)), "application/vnd.android.package-archive");
getActivity().startActivity(intent);
While I haven't been able to get the first approach to work, the second attempt creates a system dialog asking the user to confirm the installation (so almost there, but not quite). Since it is a System dialog, I, unfortunately, cannot use Robotium to confirm.

A lot of people are trying to solve similar problems. I believe it may not be possible to install an APK without confirmation, at least not easily:
Silent installation on Android devices
I've accepted for a while now that it's impossible to silently install an application on Android
Install apps silently, with granted INSTALL_PACKAGES permission
You cannot silently install app, its not supported by Android for obvious reasons. Application installation requires user intervention to continue.
Workarounds?
You need the app to have the android.permission.INSTALL_PACKAGES permission.
There are some hints on those threads about how to do this if you have certain priveleges, though it might be hard to get your app to run that way. You might have to install to a special directory, and/or you might have to run as a special user (which might be hard to do).
One possible way to run the app with elevated permissions: How can I get root permissions through the Android SDK?
On this thread, they mention you might have to "root" your phone to enable that permission:
http://www.anddev.org/androidpermissioninstall_packages_not_granted-t5858.html
I wouldn't be surprised if this voids the warranty though. You mentioned in the comments on your post that you don't have "control over the device", so that might kill this option too.
There is some mention on this thread of exploits that some apps use, but I don't think they're supported. If they still work, they might stop working at some point.

I'm trying to do the same thing, in order to push updates to devices we control. In our case they're already rooted, and the application has been granted superuser, so I think just copying the .apk over the top of the existing file would probably work, but this seems very hacky.
What seems like a better approach (if it works) is to use the pm Package Manager application:
# /system/bin/pm
usage: pm [list|path|install|uninstall]
pm list packages [-f]
pm list permission-groups
pm list permissions [-g] [-f] [-d] [-u] [GROUP]
pm list instrumentation [-f] [TARGET-PACKAGE]
pm list features
pm path PACKAGE
pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH
pm uninstall [-k] PACKAGE
pm enable PACKAGE_OR_COMPONENT
pm disable PACKAGE_OR_COMPONENT
pm setInstallLocation [0/auto] [1/internal] [2/external]
The list packages command prints all packages. Options:
-f: see their associated file.
The list permission-groups command prints all known
permission groups.
The list permissions command prints all known
permissions, optionally only those in GROUP. Options:
-g: organize by group.
-f: print all information.
-s: short summary.
-d: only list dangerous permissions.
-u: list only the permissions users will see.
The list instrumentation command prints all instrumentations,
or only those that target a specified package. Options:
-f: see their associated file.
The list features command prints all features of the system.
The path command prints the path to the .apk of a package.
The install command installs a package to the system. Options:
-l: install the package with FORWARD_LOCK.
-r: reinstall an exisiting app, keeping its data.
-t: allow test .apks to be installed.
-i: specify the installer package name.
-s: install package on sdcard.
-f: install package on internal flash.
The uninstall command removes a package from the system. Options:
-k: keep the data and cache directories around.
after the package removal.
The enable and disable commands change the enabled state of
a given package or component (written as "package/class").
The getInstallLocation command gets the current install location
0 [auto]: Let system decide the best location
1 [internal]: Install on internal device storage
2 [external]: Install on external media
The setInstallLocation command changes the default install location
0 [auto]: Let system decide the best location
1 [internal]: Install on internal device storage
2 [external]: Install on external media

Related

Xamarin Android pm install not working programmatically [duplicate]

I tried updating an APK using this code:
Process process;
process = Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r -d"+MyApk.apk});
but it does not work.
This works well when I use it with adb like:
adb shell su -c pm install -r -d /system/app/Community-debug.apk
It also works fine if it has to ask for user permission in order to install like using the intent method.
Your application would need to run as System user to access this level of commands. It cannot be done in any way if your app is distributed using standard channels, e.g. Google Play, installing from SD card, or installing by ADB. None of these would let your app breach the security.
Having said that, there is a way to get it working, but that way is for privileged distribution only. Your app must:
include android:sharedUserId="android.uid.system" in the AndroidManifest
be signed with the certificate which is used to sign the rest of the system
be pre-installed in one of the privileged locations: /system/app, /system/priv-app
Once your app satisfies these requirements, it can execute commands like pm install, even without the su
Needless to say that such options are only available to large bodies like telecom providers who sell their own-branded devices.
Your solution will only work on rooted devices.
In order for it to run on all devices, firstly, you need a cooperation from the device manufacturer to put your app under /system/priv-app. Putting your apk there will give you system privileges enabling you to perform the install.
On top of that, you need to add android.permission.INSTALL_PACKAGES to your manifest file.
Finally, add these lines to your code:
Runtime.getRuntime().exec("chmod 777 " + MyApk.apk);
Process process = Runtime.getRuntime().exec("pm install -r " + MyApk.apk);

Install apk on Termux and wait for it to finish OR check whether apk is installed

In Termux I am installing several apk's using
xdg-open myapp.apk
and I want to make sure it actually happens, ie that the resulting install window doesn't disappear and ideally that the user was successful (chose to install it). Instead, my script immediately continues, leaving the installation to go on in the background and maybe not happen.
I would like to ask the OS whether the app is installed, or have it complete the installation before continuing.
How to check if APK is installed: if device is rooted - tsudo pm list packages | grep my.package.id
How to install APK - if device is rooted: tsudo pm install mypackage.apk
(you will need to install tsudo beforehand).
For non-rooted devices it is seemingly impossible to know if certain app is installed - most likely for security reasons.
Installing on non-rooted devices works with xdg-open, but only after you permit installing from untrusted sources in Android preferences for Termux app. And Termux should be active for it to work. (Termux-floating window or SSH won't work, unless main Termux window is active.)

Installing an APK using pm command

I tried updating an APK using this code:
Process process;
process = Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r -d"+MyApk.apk});
but it does not work.
This works well when I use it with adb like:
adb shell su -c pm install -r -d /system/app/Community-debug.apk
It also works fine if it has to ask for user permission in order to install like using the intent method.
Your application would need to run as System user to access this level of commands. It cannot be done in any way if your app is distributed using standard channels, e.g. Google Play, installing from SD card, or installing by ADB. None of these would let your app breach the security.
Having said that, there is a way to get it working, but that way is for privileged distribution only. Your app must:
include android:sharedUserId="android.uid.system" in the AndroidManifest
be signed with the certificate which is used to sign the rest of the system
be pre-installed in one of the privileged locations: /system/app, /system/priv-app
Once your app satisfies these requirements, it can execute commands like pm install, even without the su
Needless to say that such options are only available to large bodies like telecom providers who sell their own-branded devices.
Your solution will only work on rooted devices.
In order for it to run on all devices, firstly, you need a cooperation from the device manufacturer to put your app under /system/priv-app. Putting your apk there will give you system privileges enabling you to perform the install.
On top of that, you need to add android.permission.INSTALL_PACKAGES to your manifest file.
Finally, add these lines to your code:
Runtime.getRuntime().exec("chmod 777 " + MyApk.apk);
Process process = Runtime.getRuntime().exec("pm install -r " + MyApk.apk);

Android: How do I uninstall a platform-signed package via the command line

I'm running on a device with a custom Android platform for which I have the platform.keystore certificate. I was able to build an application, sign it with the platform key, and install it on my device. However, now that the package has been installed, I can't seem to uninstall it from the command line.
Since the device is running a production build of the OS, I can't run adb root from the command line to gain permissions. Also, I'm unable to run su from adb shell since I don't have permissions, so I can't go into /data/data and force remove the package.
I can think of a couple ways of uninstalling the package NOT from the command line:
Go into Settings->Apps and click Uninstall
Create another platform-signed app that uses reflection to access the uninstall API from PackageManager to uninstall it. Along these same lines, I could have the app send an Intent to PackageManager to prompt the user to uninstall the package.
That's great, but I'd really like to be able to uninstall the package from the command line. It seems like there should be parity here. Is there a way to uninstall a platform-signed package from the command line considering I have access to the signing certificate?
Do you know the app's package? If so, try
adb uninstall *com.name.of.package*
(as documented, for instance, at this site ).

Does Android keep the .apk files? if so where?

After android installs an application from the Marketplace, does it keep the .apk file?
Is there a standard location where Android would keep such files?
You can use package manager (pm) over adb shell to list packages:
adb shell pm list packages | sort
and to display where the .apk file is:
adb shell pm path com.king.candycrushsaga
package:/data/app/com.king.candycrushsaga-1/base.apk
And adb pull to download the apk.
adb pull data/app/com.king.candycrushsaga-1/base.apk
Preinstalled applications are in /system/app folder. User installed applications are in /data/app. I guess you can't access unless you have a rooted phone.
I don't have a rooted phone here but try this code out:
public class Testing extends Activity {
private static final String TAG = "TEST";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
File appsDir = new File("/data/app");
String[] files = appsDir.list();
for (int i = 0 ; i < files.length ; i++ ) {
Log.d(TAG, "File: "+files[i]);
}
}
It does lists the apks in my rooted htc magic and in the emu.
If you just want to get an APK file of something you previously installed, do this:
Get AirDroid from Google Play
Access your phone using AirDroid from your PC web browser
Go to Apps and select the installed app
Click the "download" button to download the APK version of this app from your phone
You don't need to root your phone, use adb, or write anything.
There is no standard location, however you can use the PackageManager to find out about packages and the ApplicationInfo class you can get from there has various information about a particular package: the path to its .apk, the path to its data directory, the path to a resource-only .apk (for forward locked apps), etc. Note that you may or may not have permission to read these directories depending on your relationship with the other app; however, all apps are able to read the resource .apk (which is also the real .apk for non-forward-locked app).
If you are just poking around in the shell, currently non-forward-locked apps are located in /data/app/.apk. The shell user can read a specific .apk, though it can't list the directory. In a future release the naming convention will be changed slightly, so don't count on it remaining the same, but if you get the path of the .apk from the package manager then you can use it in the shell.
Preinstalled Apps are typically in /system/app and user installed apps are in /data/app.
You can use "adb pull", but you need to know the full path of the APK file. On the emulator, you can get a directory listing using "adb shell" + "ls". But on an android device, you will not be able to do that in "/data" folder due to security reasons. So how do you figure out the full path of the APK file?
You can get a full list of all apps installed by writing a program that queries the PackageManager. Short code snippet below:
PackageManager pm = getPackageManager();
List<PackageInfo> pkginfo_list = pm.getInstalledPackages(PackageManager.GET_ACTIVITIES);
List<ApplicationInfo> appinfo_list = pm.getInstalledApplications(0);
for (int x=0; x < pkginfo_list.size(); x++){
PackageInfo pkginfo = pkginfo_list.get(x);
pkg_path[x] = appinfo_list.get(x).publicSourceDir; //store package path in array
}
You can also find apps that will give such info. There are lots of them. Try this one (AppSender).
Install from marketplace
It's the behavior of marketplace whether to keep the apk after installation. Google play doesn't keep the apk after the installation. Other third-party marketplaces might have the different behaviors.
Install from development/debug tool (adb, eclipse, android studio)
When we install the apk from debug tool, directly invoke adb install or from eclipse/android studio, the apk will be transferred (adb push) to a public read and writable directory, usually /data/local/tmp/. After that, the tool will use the pm command to install, it will delete the temporary apk in /data/local/tmp/ after the successful installation.
We could get these information from debug output like following.
$ adb install bin/TestApplication.apk
3155 KB/s (843375 bytes in 0.260s)
pkg: /data/local/tmp/TestApplication.apk
Success
How system keeps the apk
Of course the system have to store all apks somewhere. There are three places for the system to keep the apks based on the different types of apks:
for stock app
Those are usually shipped in device by manufacture, including core app for system running and google service, you can find them under directory /system/app and /system/priv-app.
user installed app
Most of the apks fall into this category. These apks are usually installed from marketplace by users or by adb install without -s option. You can find them under the directory /data/app for a rooted device.
app on sdcard
If the apk enable its install location in sdcard with android:installLocation="auto" in its manifest, the app can be moved to sdcard from system's app manager menu. These apks are usually located in secure folder of sdcard /mnt/sdcard/asec.
Anther way to force the install location to sdcard is using the command adb install -s apk-to-install.apk.
As a note, the files for pre-installed app are not in a single .apk file anymore. There is a folder containing files for every pre-installed app in the directory /system/app or /system/priv-app for the newest android release.
If you're looking for the path of a specific app, a quick and dirty solution is to just grep the bugreport:
$ adb bugreport | grep 'dir=/data/app'
I don't know that this will provide an exhaustive list, so it may help to run the app first.
You can pull apps with ADB. They are in /data/App/, I believe.
adb pull (location on device) (where to save)
Note that you have to root your phone to pull copy protected apps.
In /data/app but for copy protection I don't think you can access it.
If you are rooted, download the app Root Explorer. Best File manager for rooted users.
Anyways, System/app has all the default apks that came with the phone, and data/apk has all the apks of the apps you have installed. Just long press on the apk you want (while in Root Explorer), get to your /sdcard folder and just paste.
data/app
system/app
system/priv-app
mnt/asec (when installed in sdcard)
You can pull the .apks from any of them:
adb pull /mnt/asec
Use this to list all .apks under /data/app/
adb bugreport | grep 'package name="' | grep 'codePath="/data' | cut -d'"' -f4
.apk files can be located under /data/app/ directory. Using ES File Explorer we can access these .APK files.
if you are using eclipse goto DDMS and then file explorer there you will see System/Apps folder and the apks are there
When i installed my app on emulator, it showed my the .apk file in
data/app
Then I used
ls data/app //to see if it exists or
not
After you install your app just use ls command vie shell and check desired directory but it depends what kind of application you are trying to install. I used this method to Install
Point if any thing is wrong.
Another way to get the apks you can't find, on a rooted device is with rom tool box.
Make a backup using app manager then go to storage/emulated/appmanager and check either system app backup or user app backup.
To find an apk, download and Install the Bluetooth App Sender from Play store. Once installation completes open the Bluetooth App Sender. It will show all the apps (.apk) installed in your device, then you can easily transfer the app to your PC through Bluetooth.
As opposed to what's written on the chosen answer, you don't need root and it is possible to get the APKs of the installed apps, which is how I've done it on my app (here). Example:
List<PackageInfo> packages=getPackageManager().getInstalledPackages(0);
Then, for each of the items of the list, you can access packageInfo.applicationInfo.sourceDir, which is the full path of the APK of the installed app.
Install Total Commander.
Open Installed apps on the main page.
Well I came to this post because I wanted to reinstall some app I liked much.
If this is your case, just go to Google Play, and look for My Apps, the tab All, and you will find a way to reinstall some app you liked. I faced a problem that I could not find by search one app, but it was there in My apps so I could reinstall in my new mobile ;)

Categories

Resources