How to know what libraries are included in an Android project programmatically? - android

I was wondering if it is possible to find all the libraries that are included in the Android project programmatically. I am writing a library which would need info about other libraries included in the project. Any help much appreciated.

i have made a simple function, just make a call to this function when you want to have the details.
public static void checkLibrary(){
try {
Log.e(" i am in","checklibrary");
Set<String> libs = new HashSet<String>();
String mapsFile = "/proc/" + android.os.Process.myPid() + "/maps";
BufferedReader reader = new BufferedReader(new FileReader(mapsFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.endsWith(".so")) {
int n = line.lastIndexOf(" ");
libs.add(line.substring(n + 1));
}
}
Log.e("Ldd", libs.size() + " libraries:");
for (String lib : libs) {
Log.e("Ldd", lib);
}
} catch (FileNotFoundException e) {
// Do some error handling...
} catch (IOException e) {
// Do some error handling...
}
}

For future readers.
You may use Mike Penz's AboutLibraries library
Benefits
Allow to list external, internal libraries used in your project
Out of box activity or fragment with list of libraries used in your project.

Related

java.lang.NoClassDefFoundError: in javax.sound.samples dependent library Android Studio

I am developing an android based app which process speech. My app references a .jar dependency and I have successfully added that jar as a library in my project but as I run the project it gives me java.lang.NoClassDefFoundError: for an class file which is there in jar file
Basically the class file which throwing the above error imports javax.sound.sampled packages in the code.
I am working on this part since last couple of months now but didn't found any way out of this.
I have tried copying the source code of jar library into android studio and then referencing javax.sound.sampled jar to it even tried copying javax.sound.sampled source code into android and then attaching them as per flow but still no luck.
It would be nice if I get alternatives for below imports, as it will solve the issue
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFileFormat.Type;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.UnsupportedAudioFileException;
Edit:
I am facing problem here
String strFullName = "com/example/packagename/AudioFileReader.class";
Enumeration<?> configs = null;
try {
configs = Service.class.getClassLoader().getSystemResources("strFullName");
} catch (Throwable e) {
}
if (configs != null) {
while (configs.hasMoreElements()) {
URL configFileUrl = (URL) configs.nextElement();
InputStream input = null;
try {
input = configFileUrl.openStream();
} catch (Throwable e2) {
}
if (input != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try {
for (String strLine = reader.readLine(); strLine != null; strLine = reader.readLine()) {
strLine = strLine.trim();
int nPos = strLine.indexOf(35);
if (nPos >= 0) {
strLine = strLine.substring(0, nPos);
}
if (strLine.length() > 0) {
providers.add(strLine);
}
}
} catch (Throwable e22) {
}
}
}
}
Iterator<String> iterator = providers.iterator();
return iterator;
}
It gives me TwoEnumerationsInOne and configs.hasMoreElements() gives false so not able to go into while loop.
AudioFileReader.java is included in the package
Thanks in advance.

How to get specific information of an Android device from "/proc/cpuinfo" file?

How can I parse /proc/cpuinfo virtual file of my Android tablet to get information of the processor's core and clockspeed?
I don’t need all information provided by the above file; just these two bits.
Can someone please help?
It is not clear if you want this information inside your app, or just for your own use.
you can get this information on with adb:
adb shell cat /proc/cpuinfo
If you want to use this information in your app, create a simple function to return a Map<String,String>, for example,
public static Map<String, String> getCpuInfoMap() {
Map<String, String> map = new HashMap<String, String>();
try {
Scanner s = new Scanner(new File("/proc/cpuinfo"));
while (s.hasNextLine()) {
String[] vals = s.nextLine().split(": ");
if (vals.length > 1) map.put(vals[0].trim(), vals[1].trim());
}
} catch (Exception e) {Log.e("getCpuInfoMap",Log.getStackTraceString(e));}
return map;
}
Note, this will not get multiple cpus information, overwrites. Most of the values are similar anyways. or Modify to create List of CpuInfoMaps.
try,
Log.d("getCpuInfoMap test", getCpuInfoMap().toString());
I hope its not too late for an answer but, this is how i get the current frequency for a specific cpu core:
public class MainActivity extends Activity{
private static final int INSERTION_POINT = 27;
private static String getCurFrequencyFilePath(int whichCpuCore){
StringBuilder filePath = new StringBuilder("/sys/devices/system/cpu/cpu/cpufreq/scaling_cur_freq");
filePath.insert(INSERTION_POINT, whichCpuCore);
return filePath.toString();
}
public static int getCurrentFrequency(int whichCpuCore){
int curFrequency = -1;
String cpuCoreCurFreqFilePath = getCurFrequencyFilePath(whichCpuCore);
if(new File(cpuCoreCurFreqFilePath).exists()){
try {
BufferedReader br = new BufferedReader(new FileReader(new File(cpuCoreCurFreqFilePath)));
String aLine;
while ((aLine = br.readLine()) != null) {
try{
curFrequency = Integer.parseInt(aLine);
}
catch(NumberFormatException e){
Log.e(getPackageName(), e.toString());
}
}
if (br != null) {
br.close();
}
}
catch (IOException e) {
Log.e(getPackageName(), e.toString());
}
}
return curFrequency;
}
}
From here its a piece of cake, you simply call the method :-D
int core1CurrentFreq = getCurrentFrequency(1, this);
Sometimes the cores go offline, in which case the file path will not exist and -1 will be returned
NOTE. the returned value is in KHz
MHz value is core1CurrentFreq / 1e3
GHz value is core1CurrentFreq / 1e6
Some explainations on the getCurFrequencyFilePath() method since it is not all that clear.
Current frequency is usually stored in the file: scaling_cur_freq
The file path is:
"/sys/devices/system/cpu/cpu(XX)/cpufreq/scaling_cur_freq"
where (XX) is substituted for the cpu core number eg:
"/sys/devices/system/cpu/cpu2/cpufreq/scaling_cur_freq"
The INSERTION_POINT variable is nothing more than the index of (XX), the point at which we want to place the number corresponding to the cpu core
I suggest you take a look at some of the other files in the cpufreq folder, you can use them to get other information like maximum and minimum frequency, list of availables frequencies etc.
Click this
Link
and scroll down to heading 3

List values in strings.xml

I would need to List all the values in strings.xml (for a given locale),
basically get a dynamic list of all the strings in an application.
My purpose here is to list all strings of all apps inside my (duely rooted) phone in order to speed up translation work.
I have no problem accessing the AssetManager of other apps :
-To get the list of all apps I use :
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
-To access the package manager I use :
PackageManager manager = getPackageManager();
Resources mApk1Resources = manager.getResourcesForApplication(pname);
AssetManager a = mApk1Resources.getAssets();
But I am not quite sure where to go from here.
Obviously this is not for production purpose, just for helping my customer's translation team (you know Chinese OEMs...), so jackhammer-dirty solutions are welcome :-P (reflection, dynamic foreign context, live dex loading, dynamite etc...)
Thanks !
Edit 1 : I already know B.A.R.T it doesn't suit my need I need to do it on a live phone (not a zipped ROM) like a "live translation checker app". In particular, I don't have immediate access to the app's source codes, because I have to check a large number of phones, some being few years old. I can spend the time to root all of them if needed, but not much more.
Edit 2 : I really need something that runs on a live phone without the need of a PC. I can't modify the source code of individual apps and I can't decompile the ROM or use external tools like B.A.R.T I need an all-Java solution.
I can see that: usually the string for application label will get the first id in the resource strings. (not found an official document on this yet)
So the plan is: get the id of the label of an app, increase the id each time to get the next resource string until we get the Resources.NotFoundException
try {
List<ApplicationInfo> apps = getPackageManager()
.getInstalledApplications(0);
for (ApplicationInfo appInfo : apps) {
Resources mApk1Resources = getPackageManager()
.getResourcesForApplication(appInfo.packageName);
int id = appInfo.labelRes;
try {
Log.e("Test", "*******************************************");
Log.e("Test", apps.get(0).packageName);
while (true) {
Log.e("Test",
"String resource: "
+ mApk1Resources.getString(id));
id++;
}
} catch (Resources.NotFoundException e) {
// Handle exception
}
}
} catch (NameNotFoundException e) {
// Handle exception
}
Seeing you said you accept "jackhammer-dirty solutions", give this a try:
In your Strings.xml, surround all your String values with a <string-array> tag, and all string tags inside change to item tags, like so (used simple find-and-replace to replace the tag names):
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World!</string>
<string name="app_name">YourAppNAme</string>
<string-array name="yourTitle">
<item>item1</item> //used to be <string name"blabla">....
<item>item2</item>
<item>item3</item>
</string-array>
</resources>
In your xml Layout file, where you have your ListView, put:
<ListView
android:id=”#+id/yourListView”
android:layout_width=”match_parent”
android:layout_height=”wrap_content”
android:entries="#array/yourTitle"
/>
Now, your Activity where you have your List, just call the ListView which should already be populated with the items from the Strings.xml
Don't forget to revert the changes in Strings.xml once you are done (and backup is always a good idea)!
Read more Here
Hope this helps!
Since you've rooted the phone and have access to every APK in the phone, how about just decompile them and get to the strings that way, see tutorial here: http://www.miui-au.com/add-ons/apktool/
Ok, I guess I found it. Reflection did the trick !
Root was not even needed. Crazy to know that any apps on your phone can see all the other's ressources...
public void listAllStrings(){
List<PackageInfo> packs = getPackageManager().getInstalledPackages(0);
for(int i=0;i<packs.size();i++) {
PackageInfo p = packs.get(i);
String pname = p.packageName;
Resources packageResources=null;
Context packageContext=null;
try
{
packageResources = MainActivity.this.getPackageManager().getResourcesForApplication(pname);
packageContext = MainActivity.this.createPackageContext(pname, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
}
catch(NameNotFoundException excep)
{
// the package does not exist. move on to see if another exists.
Log.e(pname, "Package not found!");
}
Class<?> stringClass=null;
try
{
// using reflection to get the string class inside the R class of the package
stringClass = packageContext.getClassLoader().loadClass(pname + ".R$string");
}
catch (ClassNotFoundException excep1)
{
// Less chances that class won't be there.
Log.e(pname, "R.string not found!");
}
if(stringClass!=null){
//For every fields of the string class
for( Field stringID : stringClass.getFields() )
{
try
{
//We get the id
int id = stringID.getInt(stringClass);
//We get the string value itself
String xmlResourceLayout = packageResources.getString(id);
Log.v(pname, xmlResourceLayout);
}
catch (Exception excep)
{
Log.e(pname, "Can't access : "+stringID.getName());
continue;
}
}
}
}
}
Hope this can help others :-)
Edit : For some Apks, the R class is not at the root of the package, so I had to write a find-R function
String findR(Context packageContext){
try {
//First case, the R class is easy to find !
packageContext.getClassLoader().loadClass(packageContext.getPackageName() + ".R");
return packageContext.getPackageName() + ".R";
} catch (Exception e) {
//Second case, it is not at the root of the package, we will list all classes...
Log.v(packageContext.getPackageName(),"R not found... Continue searching !");
try {
final PackageManager pm = getApplicationContext().getPackageManager();
ApplicationInfo ai = pm.getApplicationInfo(packageContext.getPackageName(), 0);
DexFile dx = DexFile.loadDex(ai.sourceDir, File.createTempFile("opt", "dex",
getCacheDir()).getPath(), 0);
String pathToR=null;
// Search inside each and every class in the dex file
for(Enumeration<String> classNames = dx.entries(); classNames.hasMoreElements();) {
String className = classNames.nextElement();
//for every single class, we will see if one of the fields is called app_name
//Log.v(className, "Class detail : "+className);
if(className.contains("R$string")) pathToR=className;
}
if(pathToR==null) throw new ClassNotFoundException();
pathToR=pathToR.replaceAll("$string", "");
Log.v(packageContext.getPackageName(), "R FOUND ! "+packageContext.getPackageName());
return pathToR;
} catch (Exception exc) {
Log.e(packageContext.getPackageName(), "ERROR ! R NOT FOUND ...");
return null;
}
}
}
But it still doesn't work in every case. So I ended hijacking the apktools library so it could run live on a phone... (I used the jar from 1.5.2 http://code.google.com/p/android-apktool/downloads/detail?name=apktool1.5.2.tar.bz2&can=2&q=) Here is my hijacked class :
public class Decoder {
public void decode(ResTable resTable, ExtFile apkFile, File outDir)
throws AndrolibException {
Duo<ResFileDecoder, AXmlResourceParser> duo = getResFileDecoder();
ResFileDecoder fileDecoder = duo.m1;
ResAttrDecoder attrDecoder = duo.m2.getAttrDecoder();
attrDecoder.setCurrentPackage(resTable.listMainPackages().iterator()
.next());
Directory inApk, in = null, out;
try {
inApk = apkFile.getDirectory();
out = new FileDirectory(outDir);
Log.v(MainActivity.SMALL_TAG,"Decoding AndroidManifest.xml with resources...");
fileDecoder.decodeManifest(inApk, "AndroidManifest.xml", out,
"AndroidManifest.xml");
// fix package if needed
adjust_package_manifest(resTable, outDir.getAbsolutePath()
+ "/AndroidManifest.xml");
if (inApk.containsDir("res")) {
in = inApk.getDir("res");
}
out = out.createDir("res");
} catch (DirectoryException ex) {
throw new AndrolibException(ex);
}
ExtMXSerializer xmlSerializer = getResXmlSerializer();
for (ResPackage pkg : resTable.listMainPackages()) {
attrDecoder.setCurrentPackage(pkg);
//Log.v(MainActivity.SMALL_TAG,"Decoding file-resources...");
//for (ResResource res : pkg.listFiles()) {
// fileDecoder.decode(res, in, out);
//}
Log.v(MainActivity.SMALL_TAG,"Decoding values */* XMLs...");
for (ResValuesFile valuesFile : pkg.listValuesFiles()) {
generateValuesFile(valuesFile, out, xmlSerializer);
}
generatePublicXml(pkg, out, xmlSerializer);
Log.v(MainActivity.SMALL_TAG,"Done.");
}
AndrolibException decodeError = duo.m2.getFirstError();
if (decodeError != null) {
throw decodeError;
}
}
public Duo<ResFileDecoder, AXmlResourceParser> getResFileDecoder() {
ResStreamDecoderContainer decoders = new ResStreamDecoderContainer();
decoders.setDecoder("raw", new ResRawStreamDecoder());
//decoders.setDecoder("9patch", new Res9patchStreamDecoder());
//TODO THIS DECODER CREATES ALL PROBLEMS !
AXmlResourceParser axmlParser = new AXmlResourceParser();
axmlParser.setAttrDecoder(new ResAttrDecoder());
decoders.setDecoder("xml", new XmlPullStreamDecoder(axmlParser,
getResXmlSerializer()));
return new Duo<ResFileDecoder, AXmlResourceParser>(new ResFileDecoder(
decoders), axmlParser);
}
public static final String PROPERTY_SERIALIZER_INDENTATION = "http://xmlpull.org/v1/doc/properties.html#serializer-indentation";
public static final String PROPERTY_SERIALIZER_LINE_SEPARATOR = "http://xmlpull.org/v1/doc/properties.html#serializer-line-separator";
public static final String PROPERTY_DEFAULT_ENCODING = "DEFAULT_ENCODING";
public ExtMXSerializer getResXmlSerializer() {
ExtMXSerializer serial = new ExtMXSerializer();
serial.setProperty(PROPERTY_SERIALIZER_INDENTATION,
" ");
serial.setProperty(PROPERTY_SERIALIZER_LINE_SEPARATOR,
System.getProperty("line.separator"));
serial.setProperty(PROPERTY_DEFAULT_ENCODING, "utf-8");
serial.setDisabledAttrEscape(true);
return serial;
}
public void adjust_package_manifest(ResTable resTable, String filePath)
throws AndrolibException {
// check if packages different, and that package is not equal to
// "android"
Map<String, String> packageInfo = resTable.getPackageInfo();
if ((packageInfo.get("cur_package").equalsIgnoreCase(
packageInfo.get("orig_package")) || ("android"
.equalsIgnoreCase(packageInfo.get("cur_package")) || ("com.htc"
.equalsIgnoreCase(packageInfo.get("cur_package")))))) {
Log.v(MainActivity.SMALL_TAG,"Regular manifest package...");
} else {
try {
Log.v(MainActivity.SMALL_TAG,"Renamed manifest package found! Fixing...");
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filePath.toString());
// Get the manifest line
Node manifest = doc.getFirstChild();
// update package attribute
NamedNodeMap attr = manifest.getAttributes();
Node nodeAttr = attr.getNamedItem("package");
mPackageRenamed = nodeAttr.getNodeValue();
nodeAttr.setNodeValue(packageInfo.get("cur_package"));
// re-save manifest.
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filePath));
transformer.transform(source, result);
} catch (ParserConfigurationException ex) {
throw new AndrolibException(ex);
} catch (TransformerException ex) {
throw new AndrolibException(ex);
} catch (IOException ex) {
throw new AndrolibException(ex);
} catch (SAXException ex) {
throw new AndrolibException(ex);
}
}
}
private void generatePublicXml(ResPackage pkg, Directory out,
XmlSerializer serial) throws AndrolibException {
try {
OutputStream outStream = out.getFileOutput("values/public.xml");
serial.setOutput(outStream, null);
serial.startDocument(null, null);
serial.startTag(null, "resources");
for (ResResSpec spec : pkg.listResSpecs()) {
serial.startTag(null, "public");
serial.attribute(null, "type", spec.getType().getName());
serial.attribute(null, "name", spec.getName());
serial.attribute(null, "id",
String.format("0x%08x", spec.getId().id));
serial.endTag(null, "public");
}
serial.endTag(null, "resources");
serial.endDocument();
serial.flush();
outStream.close();
} catch (IOException ex) {
throw new AndrolibException("Could not generate public.xml file",
ex);
} catch (DirectoryException ex) {
throw new AndrolibException("Could not generate public.xml file",
ex);
}
}
private void generateValuesFile(ResValuesFile valuesFile, Directory out,
ExtXmlSerializer serial) throws AndrolibException {
try {
OutputStream outStream = out.getFileOutput(valuesFile.getPath());
serial.setOutput((outStream), null);
serial.startDocument(null, null);
serial.startTag(null, "resources");
for (ResResource res : valuesFile.listResources()) {
if (valuesFile.isSynthesized(res)) {
continue;
}
((ResValuesXmlSerializable) res.getValue())
.serializeToResValuesXml(serial, res);
}
serial.endTag(null, "resources");
serial.newLine();
serial.endDocument();
serial.flush();
outStream.close();
} catch (IOException ex) {
throw new AndrolibException("Could not generate: "
+ valuesFile.getPath(), ex);
} catch (DirectoryException ex) {
throw new AndrolibException("Could not generate: "
+ valuesFile.getPath(), ex);
}
}
private String mPackageRenamed = null;
}
and here's how I use it :
String pname = p.packageName;
Context packageContext = MainActivity.this.createPackageContext(pname, Context.CONTEXT_INCLUDE_CODE + Context.CONTEXT_IGNORE_SECURITY);
ApplicationInfo ai = packageContext.getApplicationInfo();
Log.v(TAG,"Analysing : "+pname+" "+ai.sourceDir);
if(new File(destination.getAbsolutePath()+"/"+pname+".strings.xml").exists()){
Log.v(TAG,"Already translated...");
continue;
}
ApkDecoder decoder = new ApkDecoder();
decoder.setApkFile(new File(ai.sourceDir));
File directory = new File(Environment.getExternalStorageDirectory()+File.separator+"tempApk");
directory.mkdirs();
DeleteRecursive(directory);
directory.mkdirs();
decoder.setOutDir(directory);
decoder.setForceDelete(true);
File frmwrk = new File(Environment.getExternalStorageDirectory()+File.separator+"framework");
frmwrk.mkdirs();
decoder.setFrameworkDir(Environment.getExternalStorageDirectory()+File.separator+"framework");
decoder.setDecodeSources((short)0x0000);
decoder.setKeepBrokenResources(true);
try{
//decoder.decode();
new Decoder().decode(decoder.getResTable(), new ExtFile(new File(ai.sourceDir)), directory);
} catch (Throwable e) {
e.printStackTrace();
}
Lots of headaches for few Strings ;-)

How to obtain library information using Android NDK?

Using Android NDK is it possible (from native C-code) to get a list of loaded .so libraries? I am looking for an Android-version of the iOS functions _dyld_image_count()/_dyld_get_image_name().
Also is it possible to get the library name of the .so containing a specific function (on iOS this function is dladdr()).
You can read and parse /proc/self/maps file. It contains which address each shared object loaded for your application. self will help your application to read its own info.
nm command line utiliy which is also available in Android NDK can show you which symbols are available from certain shared object files. You can look how it is implemented and try to utilize the same libraries, but it won't be trivial.
Yes you can Get this Here is Sample
try {
Set<String> libs = new HashSet<String>();
String mapsFile = "/proc/" + android.os.Process.myPid() + "/maps";
BufferedReader reader = new BufferedReader(new
FileReader(mapsFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.endsWith(".so")) {
int n = line.lastIndexOf(" ");
libs.add(line.substring(n + 1));
}
}
Log.d("Ldd", libs.size() + " libraries:");
for (String lib : libs) {
Log.d("Ldd", lib);
}
} catch (FileNotFoundException e) {
// Do some error handling...
} catch (IOException e) {
// Do some error handling...
}
try this This Might Help You

specific android processor details

I have gone through the forums and got a method to get the android processor information as a string! well, it returns lots of information that is irrelevant to a user. I want to get the specific details only like
Processor Name or type
Avilabale cores
Cache size
Processor Version
this is the method I found to get the information! if any one can tell me a way to get specific details please help me! :)
private String getInfo() {
StringBuffer sb = new StringBuffer();
sb.append("abi: ").append(Build.CPU_ABI).append("\n");
if (new File("/proc/cpuinfo").exists()) {
try {
BufferedReader br = new BufferedReader(new FileReader(new File("/proc/cpuinfo")));
String aLine;
while ((aLine = br.readLine()) != null) {
sb.append(aLine + "\n");
}
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
and I'm kinda new to android app development so please help me in this! :) ( MY research project )
I'm getting the Processor namefrom the available details. You can change what you want.
while ((aLine = br.readLine()) != null) {
if(aLine.contains("Processor"))
{
String pro=aLine;
Log.v("Processor>>>",pro);
}
sb.append(aLine + "\n");
}

Categories

Resources