I'm trying to figure out how to get the size of an installed app.
What's already failed:
- new File('/data/app/some.apk')
- reports incorrect size
- PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer)
- is @hide
and relies on some obscure IPackageStatsObserver
for result so I can't call it via reflection.

- 56,576
- 33
- 147
- 165
-
I use this as fallback for getPackageSizeInfo(), this work also on non rooted phones. – ATom Nov 29 '11 at 15:58
-
@CommonsWare Actually it does work (at least on all the cases I've tried). It gets the size of the APK file, and you can even copy this file. You can check this out on an app I've made (here: https://play.google.com/store/apps/details?id=com.lb.app_manager ) , and avoid giving it root permission. On the app, try to share an APK file. I think sharing the APK won't work for protected/purchased apps, but getting the APK files sizes actually does work on all the cases I've tried. Weird. – android developer Apr 21 '14 at 15:45
6 Answers
Unfortunately there is currently no official way to do that. However, you can call the PackageManager
's hidden getPackageSize
method if you import the PackageStats
and IPackageStatsObserver
AIDLs into our project and generate the stubs. You can then use reflection to invoke getPackageSize
:
PackageManager pm = getPackageManager();
Method getPackageSizeInfo = pm.getClass().getMethod(
"getPackageSizeInfo", String.class, IPackageStatsObserver.class);
getPackageSizeInfo.invoke(pm, "com.android.mms",
new IPackageStatsObserver.Stub() {
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
Log.i(TAG, "codeSize: " + pStats.codeSize);
}
});
That's obviously a big hack and should not be used for public applications.

- 74,165
- 16
- 97
- 99
-
4I found that some device doesn't have getPackageSizeInfo() then you get this java.lang.NoSuchMethodException: getPackageSizeInfo() – ATom Nov 29 '11 at 15:56
-
-
Thanks. I was doing some another task but needed to use these two aidls. But for PackageStats I was copying .java file instead of aidls, and was fighting with unsolvable import :). Thanks for the line `you import the PackageStats and IPackageStatsObserver AIDLs`.. – Pankaj Kumar Apr 07 '14 at 08:31
-
how to import PackageStats And ipackageStatsObserver AIDLS can someone pls help me ? @Josef Pfleger – Erum Nov 20 '14 at 04:10
-
7not working anymore in Android N: https://code.google.com/p/android/issues/detail?id=222516&sort=-opened&colspec=ID%20Status%20Priority%20Owner%20Summary%20Stars%20Reporter%20Opened – Anthea Dec 07 '16 at 09:36
-
@Anthea Seems to work fine for me on Android 7.1.2, but not on Android O. Any idea of how to fix this? – android developer Apr 11 '17 at 10:16
-
1From 8.0 **getPackageSizeInfo** is depricated. So use **StorageStatsmanager**. [refer this link](https://stackoverflow.com/questions/49606077/android-packagestats-gives-always-zero) – BHARADWAJ Marripally Jun 13 '18 at 11:49
-
@BHARADWAJMarripally app is crashing when i used StorageStatsmanager java.lang.NoSuchMethodException: StorageStatsmanager [class java.lang.String, interface android.content.pm.IPackageStatsObserver] – Mohd Saquib Aug 02 '18 at 11:01
-
@MohdSaquib You have to handle this with if condition. for 8.0 and above use StorageStatsmanager and for below 8.0 use getPackageSizeInfo – BHARADWAJ Marripally Aug 29 '18 at 11:44
You can do it simplier by gettting path to apk file, and checking its lenght:
final PackageManager pm = context.getPackageManager();
ApplicationInfo applicationInfo = pm.getApplicationInfo(context.getPackageName(), 0);
File file = new File(applicationInfo.publicSourceDir);
long size = file.length();

- 179
- 4
- 18

- 377
- 5
- 13
-
7That's the size of the APK file. What about the rest of the files each app is using : cache, database, downloaded content, ...? – android developer Apr 21 '14 at 14:49
-
5
-
-
1file size is always in long not in int... correct that file.length() will return a long value – Harvinder Singh Oct 04 '19 at 08:39
Here is additional answer @Josef Pfleger 's, for comment
“I found that some device doesn't have getPackageSizeInfo() then you get this java.lang.NoSuchMethodException: getPackageSizeInfo()” @ ATom Nov 29 '11 at 15:56.
After api 16( Build.VERSION.SDK_INT >16),the method
PackageManager.getPackageSizeInfo(String packageName, IPackageStatsObserver observer);
changed into:
PackageManager.getPackageSizeInfo(String packageName, int userHandle, IPackageStatsObserver observer);
And the explain for the new added param userHandle
is :The user whose size information should be retrieved.
So we should do it like this:
int sysVersion= Build.VERSION.SDK_INT;
if (pkgName != null) {// packageName
PackageManager pm = getPackageManager();
try {
Class<?> clz = pm.getClass();
if (sysVersion>16) {
Method myUserId=UserHandle.class.getDeclaredMethod("myUserId");//ignore check this when u set ur min SDK < 17
int userID = (Integer) myUserId.invoke(pm);
Method getPackageSizeInfo = clz.getDeclaredMethod(
"getPackageSizeInfo", String.class,int.class,
IPackageStatsObserver.class);//remember add int.class into the params
getPackageSizeInfo.invoke(pm,pkgName, userID, new PkgSizeObserver());
} else {//for old API
Method getPackageSizeInfo = clz.getDeclaredMethod(
"getPackageSizeInfo", String.class,
IPackageStatsObserver.class);
getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
}
} catch (Exception ex) {
Log.e(TAG, "NoSuchMethodException");
ex.printStackTrace();
throw ex;}
The class needed to callback like:
private class PkgSizeObserver extends IPackageStatsObserver.Stub {
/***
* @param pStatus
* @param succeeded
*/
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
cachesize = pStats.cacheSize;//remember to declare these fields
datasize = pStats.dataSize;
codesize = pStats.codeSize;
totalsize = cachesize + datasize + codesize;
Log.i("123","cachesize--->" + cachesize + " datasize---->"
+ datasize + " codeSize---->" + codesize);
}
}
And use this method to parse long2string,then you can see xx MB
instead of long
like 2342334 :)
private String formateFileSize(long size) {
return Formatter.formatFileSize(MainActivity.this, size);
}

- 141
- 1
- 9
-
Hello droida, I can't seem to get it to work, I keep getting Android Studio sayin it can't resolve symbol `IPackageStatsObserver`, allthough I think I got through all the steps indicated by both @Josef Pfleger and you @droida Any suggestions? – CMPSoares Jun 20 '16 at 04:27
-
Hi @CMPSoares,have you tried to import the AIDLs (http://www-jo.se/f.pfleger/using-aidl)? – droida Jun 20 '16 at 07:30
-
Yes @droida into the package/folder android.content.pm is that correct? – CMPSoares Jun 20 '16 at 09:00
-
Hi dude,perhaps you can dig out if any API changed in Android O,then make it and post out to save remaining guys' time : ) @androiddeveloper – droida Apr 12 '17 at 03:08
-
1@droida I don't think they wrote about it. I tried finding about it, but failed. I think the reason is that it's already hidden API, so it's not supposed to be used. However, I tried to debug, and it did find the method with the 2 parameters (not the 3 parameters), yet when I call it, I get succeeded==false and pStats==null. Maybe they have a bug or something, as I reported here: https://issuetracker.google.com/issues/37237952 . Anyway, I requested an official API here: https://issuetracker.google.com/issues/37238101 – android developer Apr 12 '17 at 05:32
Remember the needed permission, I solved these issues by adding the following permission to the manifest:
< uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
Or this wrong: not use getDeclaredMethod()
,should be use getMethod()
.
Method getPackageSizeInfo = mPackageManager.getClass().getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
-
It's EXACTLY what I need, because having the `java.lang.reflect.InvocationTargetException` error without it, thanks a lot! – Acuna Nov 16 '17 at 19:07
You can get Size of apps without AIDL Files -------> Kotlin Language
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val intent = Intent(Intent.ACTION_MAIN)
intent.addCategory(Intent.CATEGORY_LAUNCHER)
val list = packageManager.queryIntentActivities(intent,0)
// Set adapter to LIST VIEW
listView.adapter = getApps(list)
}
private fun getApps(List: MutableList<ResolveInfo>): List<AppData> {
val list = ArrayList<AppData>()
for (packageInfo in List) {
val packageName = packageInfo.activityInfo.packageName
// return size in form of Bytes(Long)
val size = File(packageManager.getApplicationInfo(packageName,0).publicSourceDir).length()
val item = AppData(Size)
list += item
}
return list
}
}
// Make Data Class
data class AppData(val size: Long)
Remember to convert it in MB from Bytes

- 82
- 10
package inc.xiomi.apkextrator.entity;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageStats;
import android.content.pm.ResolveInfo;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.util.DisplayMetrics;
import android.util.Log;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.concurrent.Semaphore;
public class AppInfo implements Comparable<Object> {
private Context ctx;
private ResolveInfo ri;
private ComponentName componentName = null;
private PackageInfo pi = null;
private Drawable icon = null;
String size = null;
String name = null;
// Code size will be here
long codeSize = 0;
PackageManager packageManager;
// Semaphore to handle concurrency
Semaphore codeSizeSemaphore = new Semaphore(1, true);
public AppInfo(Context ctx, ResolveInfo ri) {
this.ctx = ctx;
this.ri = ri;
packageManager = ctx.getPackageManager();
this.componentName = new ComponentName(ri.activityInfo.applicationInfo.packageName, ri.activityInfo.name);
try {
pi = ctx.getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (NameNotFoundException e) {
}
}
public String getName() {
if (name != null) {
return name;
} else {
try {
return getNameFromResolveInfo(ri);
} catch (NameNotFoundException e) {
return getPackageName();
}
}
}
public String getSize() {
if (size != null) {
return size;
} else {
try {
return getSizeFromResolveInfo(ri);
} catch (Exception e) {
return getPackageName();
}
}
}
public String getActivityName() {
return ri.activityInfo.name;
}
public String getPackageName() {
return ri.activityInfo.packageName;
}
public ComponentName getComponentName() {
return componentName;
}
public String getComponentInfo() {
if (getComponentName() != null) {
return getComponentName().toString();
} else {
return "";
}
}
public ResolveInfo getResolveInfo() {
return ri;
}
public PackageInfo getPackageInfo() {
return pi;
}
public String getVersionName() {
PackageInfo pi = getPackageInfo();
if (pi != null) {
return pi.versionName;
} else {
return "";
}
}
public int getVersionCode() {
PackageInfo pi = getPackageInfo();
if (pi != null) {
return pi.versionCode;
} else {
return 0;
}
}
public Drawable getIcon() {
if (icon == null) {
icon = getResolveInfo().loadIcon(ctx.getPackageManager());
/*
Drawable dr = getResolveInfo().loadIcon(ctx.getPackageManager());
Bitmap bitmap = ((BitmapDrawable) dr).getBitmap();
icon = new BitmapDrawable(ctx.getResources(), AppHelper.getResizedBitmap(bitmap, 144, 144));
*/
}
return icon;
}
@SuppressLint("NewApi")
public long getFirstInstallTime() {
PackageInfo pi = getPackageInfo();
if (pi != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
return pi.firstInstallTime;
} else {
return 0;
}
}
@SuppressLint("NewApi")
public long getLastUpdateTime() {
PackageInfo pi = getPackageInfo();
if (pi != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.GINGERBREAD) {
return pi.lastUpdateTime;
} else {
return 0;
}
}
@Override
public int compareTo(Object o) {
AppInfo f = (AppInfo) o;
return getName().compareTo(f.getName());
}
@Override
public String toString() {
return getName();
}
/**
* Helper method to get an applications name!
*
* @param ri
* @return
* @throws android.content.pm.PackageManager.NameNotFoundException
*/
public String getNameFromResolveInfo(ResolveInfo ri) throws NameNotFoundException {
String name = ri.resolvePackageName;
if (ri.activityInfo != null) {
Resources res = ctx.getPackageManager().getResourcesForApplication(ri.activityInfo.applicationInfo);
Resources engRes = getEnglishRessources(res);
if (ri.activityInfo.labelRes != 0) {
name = engRes.getString(ri.activityInfo.labelRes);
if (name == null || name.equals("")) {
name = res.getString(ri.activityInfo.labelRes);
}
} else {
name = ri.activityInfo.applicationInfo.loadLabel(ctx.getPackageManager()).toString();
}
}
return name;
}
public String getSizeFromResolveInfo(ResolveInfo ri) throws Exception {
try {
codeSizeSemaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
// Collect some other statistics
// Collect code size
try {
Method getPackageSizeInfo = packageManager.getClass().getMethod("getPackageSizeInfo",
String.class,
android.content.pm.IPackageStatsObserver.class);
getPackageSizeInfo.invoke(packageManager, ri.activityInfo.packageName,
new android.content.pm.IPackageStatsObserver.Stub() {
// Examples in the Internet usually have this method as @Override.
// I got an error with @Override. Perfectly works without it.
public void onGetStatsCompleted(PackageStats pStats, boolean succeedded)
throws RemoteException {
codeSize = pStats.codeSize;
Log.e("codeSize", codeSize + "");
codeSizeSemaphore.release();
}
});
} catch (Exception e) {
e.printStackTrace(System.err);
}
return String.valueOf(codeSize);
}
public Resources getEnglishRessources(Resources standardResources) {
AssetManager assets = standardResources.getAssets();
DisplayMetrics metrics = standardResources.getDisplayMetrics();
Configuration config = new Configuration(standardResources.getConfiguration());
config.locale = Locale.US;
return new Resources(assets, metrics, config);
}
}

- 1
-
Semaphore is used for getting concurrency.android.content.pm.IPackageStatsObserver is an aidl. – shefi Feb 27 '15 at 08:32
-
1Please [edit] in an explanation of why/how this code answers the question? Code-only answers are discouraged, because they are not as easy to learn from as code with an explanation. Without an explanation it takes considerably more time and effort to understand what was being done, the changes made to the code, if the code answers the question, etc. The explanation is important both for people attempting to learn from the answer and those evaluating the answer to see if it is valid, or worth up voting. – Makyen Feb 27 '15 at 08:33
-
1This is a very large amount of code, far more than necessary to answer the question. – Karu Sep 28 '15 at 13:27