I'm trying to get the size occupied by my application package. Every application has one location in the internal/external storage.
I want to calculate the size of the following directory, how can I do that?
I know I can use StorageStateManager on and above Oreo (API 26) devices, but how can I achieve this before oreo devices.
Application Directory : /Android/data/myapplicationpackage
I'm trying to use PackageStats but It's giving me always zero. What's the actual way to use this code?
I used the following code and it gives me all zero.
PackageStats stats = new PackageStats(context.getPackageName());
long codeSize = stats.codeSize + stats.externalCodeSize;
long dataSize = stats.dataSize + stats.externalDataSize;
long cacheSize = stats.cacheSize + stats.externalCacheSize;
long appSize = codeSize + dataSize + cacheSize;
PackageStats stats = new PackageStats(context.getPackageName());
It will only creates the packagestats object. As from the source, the constructor will do initializing the fields,
public PackageStats(String pkgName) {
packageName = pkgName;
userHandle = UserHandle.myUserId();
}
for api<26,
You need to use IPackageStatsObserver.aidl and have to invoke getPackageSizeInfo method by reflection.
PackageManager pm = getPackageManager();
Method getPackageSizeInfo = pm.getClass().getMethod(
"getPackageSizeInfo", String.class, IPackageStatsObserver.class);
getPackageSizeInfo.invoke(pm, "com.yourpackage",
new IPackageStatsObserver.Stub() {
#Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
//here the pStats has all the details of the package
}
});
Here is the complete solution for it. It works great.
from api 26,
The getPackageSizeInfo method is deprecated.
You can use this code,
#SuppressLint("WrongConstant")
final StorageStatsManager storageStatsManager = (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
final StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
try {
ApplicationInfo ai = context.getPackageManager().getApplicationInfo(packagename, 0);
StorageStats storageStats = storageStatsManager.queryStatsForUid(ai.storageUuid, info.uid);
cacheSize =storageStats.getCacheBytes();
dataSize =storageStats.getDataBytes();
apkSize =storageStats.getAppBytes();
size+=info.cacheSize;
} catch (Exception e) {}
But to use this code, You need USAGE ACCESS PERMISSION .
Related
I am using Tensorflow java API (1.8.0) where I load multiple models (in different sessions). Those models are loaded from .pb files using the SavedModelBundle.load(...) method. Those .pb files were obtained by saving Keras' models.
Let's say that I want to load 3 models A, B, C.
To do that, I implemented a java Model class :
public class Model implements Closeable {
private String inputName;
private String outputName;
private Session session;
private int inputSize;
public Model(String modelDir, String input_name, String output_name, int inputSize) {
SavedModelBundle bundle = SavedModelBundle.load(modelDir, "serve");
this.inputName = input_name;
this.outputName = output_name;
this.inputSize = inputSize;
this.session = bundle.session();
}
public void close() {
session.close();
}
public Tensor predict(Tensor t) {
return session.runner().feed(inputName, t).fetch(outputName).run().get(0);
}
}
Then I easily can instantiate 3 Model objects corresponding to my A, B and C models with this class and make predictions with those 3 models in the same java program.
I also noticed that if I have a GPU, the 3 models are loaded on it.
However, I would like only model A to be running on GPU and force the 2 others to be running on CPU.
By reading documentation and diving into the source code I didn't find a way to do so. I tried to define a new ConfigProto setting visible devices to None and instantiate a new Session with the graph but it didn't work (see code below).
public Model(String modelDir, String input_name, String output_name, int inputSize) {
SavedModelBundle bundle = SavedModelBundle.load(modelDir, "serve");
this.inputName = input_name;
this.outputName = output_name;
this.inputSize = inputSize;
ConfigProto configProto = ConfigProto.newBuilder().setAllowSoftPlacement(false).setGpuOptions(GPUOptions.newBuilder().setVisibleDeviceList("").build()).build();
this.session = new Session(bundle.graph(),configProto.toByteArray());
}
When I load the model, it uses the available GPU. Do you have any solution to this problem ?
Thank you for your answer.
According to this issue , the new source code fixed this problem. Unfortunately you will have to build from source following these instructions
Then you can test :
ConfigProto configProto = ConfigProto.newBuilder()
.setAllowSoftPlacement(true) // allow less GPUs than configured
.setGpuOptions(GPUOptions.newBuilder().setPerProcessGpuMemoryFraction(0.01).build())
.build();
SavedModelBundle bundle = SavedModelBundle.loader(modelDir).withTags("serve").withConfigProto(configProto.toByteArray()).load();
You can set the device configuration of your tensorflow graph. Here is some relevant code [source].
...
byte[] config = ConfigProto.newBuilder()
.setLogDevicePlacement(true)
.setAllowSoftPlacement(true)
.build()
.toByteArray()
Session sessions[] = new Session[numModels];
// function to move the graph definition to a new device
public static byte[] modifyGraphDef(byte[] graphDef, String device) throws Exception {
GraphDef.Builder builder = GraphDef.parseFrom(graphDef).toBuilder();
for (int i = 0; i < builder.getNodeCount(); ++i) {
builder.getNodeBuilder(i).setDevice(device);
}
return builder.build().toByteArray();
}
graphA.importGraphDef(modifyGraphDef(graphDef, "/gpu:0"));
graphB.importGraphDef(modifyGraphDef(graphDef, "/cpu:0"));
This would probably be cleaner than to do the more obvious setting of the CUDA_VISIBLE_DEVICES environment variable to "" after loading the first model.
Above given answers did not work for me.Using putDeviceCount("GPU", 0) makes TF use CPU . It is working in version 1.15.0.You can load same model to both cpu and gpu and if gpu throws Resource exhausted: OOM when allocating tensor, use the CPU model to do prediction.
ConfigProto configProtoCpu = ConfigProto.newBuilder().setAllowSoftPlacement(true).putDeviceCount("GPU", 0)
.build();
SavedModelBundle modelCpu=SavedModelBundle.loader(modelPath).withTags("serve")
.withConfigProto(configProtoCpu.toByteArray()).load();
ConfigProto configProtoGpu = ConfigProto.newBuilder().setAllowSoftPlacement(true)
.setGpuOptions(GPUOptions.newBuilder().setAllowGrowth(true).build()).build();
SavedModelBundle modelgpu = SavedModelBundle.loader(modelPath).withTags("serve")
.withConfigProto(configProtoGpu.toByteArray()).load();
TrafficStats class provides total data since boot can I directly access internet data usage from android
e.g Call history can be directly fetched from call log.
So is it possible to get internet data from internet data usage.
And how to get internet data usage on the basic of application ?
so for I know we cannot directly get internet data usage from android as we fetch call history record form call log we can get data form TrafficStats class which is since boot
To get internet data on application basic here is the simple code using packageManager to get package name of the corresponding app and using ApplicationInfo we can find the detail of the application information
final PackageManager pm = context.getPackageManager();
// get a list of installed apps.
List<ApplicationInfo> packages = pm.getInstalledApplications(0);
for (ApplicationInfo packageInfo : packages) {
// get the UID for the selected app
UID = packageInfo.uid;
String package_name = packageInfo.packageName;
Log.d("mypackagename",package_name+"");
ApplicationInfo app = null;
try {
app = pm.getApplicationInfo(package_name, 0);
} catch (PackageManager.NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String name = (String) pm.getApplicationLabel(app);
Drawable icon = pm.getApplicationIcon(app);
// internet usage for particular app(sent and received)
double received = (double) TrafficStats.getUidRxBytes(UID)
/ (1024 * 1024);
double send = (double) TrafficStats.getUidTxBytes(UID)
/ (1024 * 1024);
double totalab = received + send;}
I am using Android Studio 1.5.1 targeting Android API 18 (before Android KitKat 4.4, so I’m dealing with Dalvik, not ART runtime).
My questions are:
How to call the hidden Android method getTotalUss() using Java
reflection?
If not possible, how to find the current process USS (Unique Set Size) memory programmatically?
I am trying to use the code below to do that but I am getting a compiler error "Unexpected token" at the statement labelled //ERROR! below in the code.
ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
Map<Integer, String> pidMap = new TreeMap<Integer, String>();
for (ActivityManager.RunningAppProcessInfo runningAppProcessInfo : runningAppProcesses)
{
pidMap.put(runningAppProcessInfo.pid, runningAppProcessInfo.processName);
}
Collection<Integer> keys = pidMap.keySet();
int id= android.os.Process.myPid();
for(int key : keys)
{
if (key != id) continue;
int pids[] = new int[1];
int Uss;
pids[0] = key;
android.os.Debug.MemoryInfo[] memoryInfoArray = activityManager.getProcessMemoryInfo(pids);
for(android.os.Debug.MemoryInfo pidMemoryInfo: memoryInfoArray)
{
try {
Class c;
c = Class.forName("android.app.ActivityManager");
Method m = c.getMethod("getTotalUss", null);
Uss = m.invoke(null,int); // << == ERROR!
} catch (ClassNotFoundException e) {
}
catch (NoSuchMethodException e) {
}
catch (IllegalAccessException e) {
}
System.out.println("** Uss = " + Uss);
You're calling getMethod() on the ActivityManager class which doesn't contain a getTotalUss() method. That's why you're getting the error.
Instead, you'll want to reflectively get the method from the MemoryInfo class which has the getTotalUss() method. You'll also want to be sure to pass pidMemoryInfo as the receiver to the invoke() call. It's like calling pidMemoryInfo.getTotalUss().
Method m = android.os.Debug.MemoryInfo.class.getMethod("getTotalUss", null);
totalUss = (int) m.invoke(pidMemoryInfo,(Object[]) null);
See the documentation on Method's invoke() for more details.
I can't find how to get ListArray variables from an AndroidJavaObject in C#.
I'm trying to make a for function using a Count for the number of items in the ListArray that is stored as an AndroidJavaObject. But I need to know how to get the Count from the AndroidJavaObject and how to use it properly.
This is what I'm using to get the variables, also notice that "packages" is not an AndroidJavaObject[].
AndroidJavaClass jc = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = jc.GetStatic<AndroidJavaObject>("currentActivity");
int flag = new AndroidJavaClass("android.content.pm.PackageManager").GetStatic<int>("GET_META_DATA");
AndroidJavaObject pm = currentActivity.Call<AndroidJavaObject>("getPackageManager");
AndroidJavaObject packages = pm.Call<AndroidJavaObject>("getInstalledApplications", flag);
it's very rudimentary at this point, but it works thanks to some help from this How to get installed apps list with Unity3D?
The progress thus far stalls at getting the icon, everything else works perfect, I need a way to get either a string that links to the icon somehow, or the Texture2D of the icon. Another alternative would be a to use a AndroidJavaObject that contains a drawable as if it's a Texture2D. I have no idea how to accomplish any of this though.Another Idea I had was to convert it to another variable, like byte[] that can be transferred and converted back, but I have yet to find a method of that which works under the circumstance.
int count = packages.Call<int>("size");
AndroidJavaObject[] links = new AndroidJavaObject[count];
string[] names = new string[count];
Texture2D[] icons = new Texture2D[count];
int ii =0;
for(int i=0; ii<count;){
//get the object
AndroidJavaObject currentObject = packages.Call<AndroidJavaObject>("get", ii );
try{
//try to add the variables to the next entry
links[i] = pm.Call<AndroidJavaObject>("getLaunchIntentForPackage", currentObject.Get<AndroidJavaObject>("processName"));
names[i] = pm.Call<string>("getApplicationLabel", currentObject);
icons[i] = pm.Call<Texture2D>("getApplicationIcon", currentObject);
Debug.Log ("(" + ii + ") " + i +" "+ names[i]);
//go to the next app and entry
i++;
ii++;
}
catch
{
//if it fails, just go to the next app and try to add to that same entry.
Debug.Log("skipped "+ ii);
ii++;
}
}
I really hate to ask two questions in a row here, and I apologize for having to do so, but this is a difficult and seemingly awkward circumstance, that has little to no documentation (that I can find).
First of all the docs on the interop between Unity3D and Android are scarce at best.
The most important thing is that the only interface Unity exposes to work with java object is AndroidJavaObject and that interface has only a couple of methods defined. You can only use those ones and only those.
This means that you don't get a Count object when working with an java array and you'll still be working with AndroidJavaObject.
int count = packages.Call<int>("size"); //getting the size of the array
for( int i = 0; i < count; i++ )
{
//getting the object at location i
AndroidJavaObject currentObject = packages.Call("get", i );
//use currentObject using the same methods as before: Call, CallStatic, Get, GetStatic
}
I know this is verbose, and writing code like this is hard to test, you need to make and apk and deploy it to a device to check that it runs.
Probably a faster way of doing this is to make your own java class that does all this on the java side and expose one method that gets called from the Unity side. This way at least you get the benefit of static typing when making a jar that you'll add in the Plugins/Android folder.
I'm trying to do the same thing here, but my launcher must only show the CardBoard apps. What i've decided is to make a library in java and import it to Unity as a plugin:
This is my Java class:
public class Launcher extends UnityPlayerActivity {
private List<ApplicationInfo> cbApps;
#Override
protected void onStart() {
super.onStart();
PackageManager pm= getPackageManager();
List<ApplicationInfo> lista = pm.getInstalledApplications(PackageManager.GET_META_DATA);
cbApps= new LinkedList<ApplicationInfo>();
for(ApplicationInfo ai : lista){
Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
intentToResolve.addCategory("com.google.intent.category.CARDBOARD");
intentToResolve.setPackage(ai.packageName);
if(pm.resolveActivity(intentToResolve, 0)!=null) {
cbApps.add(ai);
}
}
}
public int getListSize(){
return cbApps.size();
}
And here my C# method:
void Start () {
AndroidJavaClass unity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer");
AndroidJavaObject currentActivity = unity.GetStatic<AndroidJavaObject> ("currentActivity");
texto.text=""+currentActivity.Call<int> ("getListSize");
}
This way I can create in Java every method that I need to acces the list. The problem I'm still having is trying to get the Texture2D of the icons. I've tried returning the Drawable from Java and accesing with a Call just as you did, but it doesn't work at all. I've been 2 days working with that, I'll let you know if I find a solution.
EDIT:
Finally I could get the images:
First in Java I created this method:
public byte[] getIcon(int i) {
BitmapDrawable icon= (BitmapDrawable)context.getPackageManager().getApplicationIcon(cbApps.get(i));
Bitmap bmp = icon.getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
return byteArray;
}
That way I can access the Byte array representing the Drawable from Unity and show it as the main texture of a Plane:
void Start () {
using (AndroidJavaClass unity = new AndroidJavaClass ("com.unity3d.player.UnityPlayer")) {
context = unity.GetStatic<AndroidJavaObject> ("currentActivity");
}
using (AndroidJavaClass pluginClass=new AndroidJavaClass("com.droiders.launcher.Launcher")) {
launcher= pluginClass.CallStatic<AndroidJavaObject>("getInstance", context);
byte[] bytes= launcher.Call<byte[]>("getIcon",0);
Texture2D tex= new Texture2D(2,2);
tex.LoadImage(bytes);
plane.GetComponent<Renderer>().material.mainTexture=tex;
}
}
Hope it helps you. It's been hard but this beast has been tamed :P
Also thanks you all for your ideas.
My aim is to write an android Library that can list all the resources (layouts, drawables. ids, etc.) of the caller application. The caller application need to pass to the library, nothing more than App Name or the package namespace.
E.g:
The MyLibrary function:
public void listDrawables(String namespace) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
String resourceNameSpace = namespace + ".R";
String drawableNamespace = resourceNameSpace + ".drawable";
final Class drawableClass = Class.forName(drawableNamespace);
Object drawableInstance = drawableClass.newInstance();
final Field[] fields = drawableClass.getDeclaredFields();
for (int i = 0, max = fields.length; i < max; i++) {
final int resourceId;
try {
resourceId = fields[i].getInt(drawableInstance);
// Use resourceId further
} catch (Exception e) {
continue;
}
}
The caller code (From the App Activity, say com.example.sample.MainActivity.java)
mylibrary.listDrawables("com.example.sample");
I have setup the MyLibrary as a dependent android library for the Sample app.
When this is run, I get this exception inside library at the Class.forName statement:
java.lang.ClassNotFoundException: com.example.sample.R.drawable
I am not able to understand fully, why library can't refer to the class. May be I missed a basic lesson in Java classpath and how build works, but isn't the class already loaded when library runs?
I would also like to know id there is any alternative way to list resources in an external library.
Since Drawable is a inner class, you need to access it by using $.
String resourceNameSpace = namespace + ".R";
String drawableNamespace = resourceNameSpace + "$drawable";