DexClassLoader, reload Code fails with Signal 7 - android

I'm trying to build a plugin-System, where DexClassLoader is fetching code from other installed apks containing fragments(my plugins), and showing them in my host. This is working quite nice.
I also like to make the plugins hotswappable, this means I can change the code from a plugin, install it new and the host will notice and will load the new code. This also works, if I'm changing the code for the first time. (Although I thought it shouldn't, it seems I've got a wrong understanding of this code:
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
)
If i'm trying it a second time with the same plugin, the host shuts down at requiredClass = classLoader.loadClass(fullName); with something like
libc Fatal signal 7 (SIGBUS) at 0x596ed4d6 (code=2), thread 28814
(ctivityapp.host)
Does anybody has a deeper insight in the functionality of DexClassLoader and may tell me, what is happening here? I'm quite stuck at this.
Heres the full code of the method loading the foreign code:
/**
* takes the name of a package as String, and tries to load the code from the corresponding akp using DexclassLaoder.
* Checking if a package is a valid plugin must be done before calling this.
* The Plugin must contain a public class UI that extends Fragment and implements plugin as a starting point for loading
* #param packageName The full name of the package, as String
* #return the plugins object if loaded, null otherwise
*/
private Plugin attachPluginToHost(String packageName) {
try {
Class<?> requiredClass = null;
final ApplicationInfo info = context.getPackageManager().getApplicationInfo(packageName,0);
final String apkPath = info.sourceDir;
final File dexTemp = context.getDir("temp_folder", 0);
final String fullName = packageName + ".UI";
boolean isLoaded = true;
// Check if class loaded
try {
requiredClass = Class.forName(fullName);
} catch(ClassNotFoundException e) {
isLoaded = false;
}
if (!isLoaded) {
final DexClassLoader classLoader = new DexClassLoader(apkPath, dexTemp.getAbsolutePath(), null, context.getApplicationContext().getClassLoader());
requiredClass = classLoader.loadClass(fullName);
}
if (null != requiredClass) {
// Try to cast to required interface to ensure that it's can be cast
final Plugin plugin = Plugin.class.cast(requiredClass.newInstance());
installedPlugins.put(plugin.getName(), plugin);
return plugin;
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
Many thanks in advance!

Not that it really matters (As nobody is actually viewing this), or that I even understand what's going on, but deleting the corresponding file of the plugin in dexTemp.getAbsolutePath() before reloading it solves the problem.
PS: Tumbleweed-Badge, YAY!

Related

Exception when downloading file from box.com - Android

I am trying to download a file using the Box android SDK. The problem seems to be with the destinationFile parameter. The box.com call is checking whether the destinationFile exists - but why? I get java.io.FileNotFoundException.
destinationFile = new File(getFilesDir(), "myfile.crs");
// destinationFile = new File(getFilesDir(),"/");
try {
BoxDownload fileDownload = mFileApi.getDownloadRequest(destinationFile, fileID)
// Optional: Set a listener to track download progress.
.setProgressListener(new ProgressListener() {
#Override
public void onProgressChanged(long numBytes, long totalBytes) {
// Update a progress bar, etc.
}
})
.send();
} catch (BoxException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
To do All the checks
Log.i(getClass().getName(),"Does File exists:"+(destinationFile.exists()?"Yes":"No"));
Log.i(getClass().getName(),"Is it A file:"+(destinationFile.isFile()?"Yes":"No"));
Log.i(getClass().getName(),"Is it Writable:"+(destinationFile.canWrite()?"Yes":"No"));
Log.i(getClass().getName(),"Is it A Readable:"+(destinationFile.canRead()?"Yes":"No"));
Log.i(getClass().getName(),"Path:"+destinationFile.getAbsolutePath());
you are most likely to found file does not exists then do this before using it.
if(!destinationFile.exists()){
try {
destinationFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
The answer was to create a new File. Then call .createNewFile() on the File instance. Then call all of the code I posted except to put run it in the background. That's why I was asking here - I was wondering if I was doing something incorrect for Android and I was. Box networking operations need to be done on a thread.
Too bad they never show this for downloading a file. Too bad there's not one example of downloading a file with the Android DSK on the web.

How to determine/get correct S Voice packet in Android

I am using Android to turn on my S Voice application in Android. As previous work, I will use the follows code to turn on it
String SVOICE_PACKAGE_NAME = "com.vlingo.midas";
String SVOICE_LISTEN_ACTION = "com.sec.action.SVOICE";
Intent intent = new Intent();
intent.setPackage(SVOICE_PACKAGE_NAME);
intent.setAction(SVOICE_LISTEN_ACTION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
try {
getApplication().startActivity(intent);
} catch (final ActivityNotFoundException e) {
e.printStackTrace();
} catch (final Exception e) {
e.printStackTrace();
}
The above code worked well in Galaxy S4 with Android 5.0. However, the issue comes from first and second lines in Galaxy S7 with Android 6.0. In Galaxy S7 with Android 6.0, the first and second lines have to modify as
SVOICE_PACKAGE_NAME = "com.samsung.voiceserviceplatform";
SVOICE_LISTEN_ACTION = "com.sec.action.SVOICE";
And also the application name S Voice with changing from "S Voice" to "S Voice App". That changing gives me a difficult work. Hence, I want to determine the S Voice App in my phone before deciding calls these function. Currently, I do not know the changing is from Android version or the device. Could you have any idea to adapt the issue in various phones: S4 and S7?
Whenever opening applications, there could be package or application name differences. Here is a standard utility method to check:
/**
* Check if the user has a package installed
*
* #param ctx the application context
* #param packageName the application package name
* #return true if the package is installed
*/
public static boolean isPackageInstalled(#NonNull final Context ctx, #NonNull final String packageName) {
if (DEBUG) {
MyLog.i(CLS_NAME, "isPackageInstalled");
}
try {
ctx.getApplicationContext().getPackageManager().getApplicationInfo(packageName, 0);
return true;
} catch (final PackageManager.NameNotFoundException e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: NameNotFoundException");
}
} catch (final NullPointerException e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: NullPointerException");
}
} catch (final Exception e) {
if (DEBUG) {
MyLog.w(CLS_NAME, "isPackageInstalled: Exception");
}
}
return false;
}
You'll need to remove my custom logging.

ooVoo SDK initialization issue

I am having an issue in my project, when I am loading oovooLibrary in my app it is not responding for 5 seconds and then crashing without any error. Please help me in this.
My code is
ooVooClient.setContext(app);
ooVooClient.setLogger(this, LoggerListener.LogLevel.Debug);
try {
// I am getting no responce for this line
mConferenceCore = ooVooClient.sharedInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
private ooVooClient sdk = null;
private ApplicationSettings settings = null;
if (!ooVooClient.isDeviceSupported()) {
return;
}
settings = new ApplicationSettings(this);
ooVooClient.setLogger(this, LogLevel.fromString(getSettings().get(ApplicationSettings.LogLevelKey)));
ooVooClient.setContext(this);
sdk = ooVooClient.sharedInstance();
Check this https://github.com/oovoodev/Android-SDK-Sample
I have fixed that issue, I was calling ooVooClient.setContext(app); from MainActivity class so it was not accepting that context - app (getApplicationContext()), So I initlialized it in MainApplication.java and stored that in static variable and used that in other classes.

How can i get the apk file name and path programmatically?

I want to get the exact file name of a program if I already know the package name of the target apk. For instance, if I know the package name of my apk, which is com.packagename, how can I get the exact path and file name of that package? Btw, i don't want to get just MY apk location, i want the location of any package name i apply. SystemTuner pro is able to do this so i know it is possible, just not sure how.
Thanks guys!
/**
* Get the apk path of this application.
* #param context any context (e.g. an Activity or a Service)
* #return full apk file path, or null if an exception happened (it should not happen)
*/
public static String getApkName(Context context) {
String packageName = context.getPackageName();
PackageManager pm = context.getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
String apk = ai.publicSourceDir;
return apk;
} catch (Throwable x) {
}
return null;
}
EDIT
In defense of catch (Throwable x) in this case. At first, now it is well-known that Checked Exceptions are Evil. At second, you cannot predict what may happen in future versions of Android. There already is a trend to wrap checked exceptions into runtime exceptions and re-throw them. (And a trend to do silly things that were unthinkable in the past.) As to the children of Error, well, if the package manager cannot find the apk that is running, it is the kind of problems for which Errors are thrown. Probably the last lines could be
} catch (Throwable x) {
return null;
}
but I do not change working code without testing it.
PackageManager.getPackageInfo() returns information about the package, and PackageInfo.applicationInfo field has required information about the application.
Well, i would like to mark Yuri as the answer but i already knew about that stuff. So I went through each and every option from PackageManager.ApplicationInfo and found .publicSourceDir
So a complete answer with code to my question would be
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pInfo.getApplicationInfo(<packageName here>, 0);
String sourceApk = ai.publicSourceDir;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
So thanks again guys, got my brain goin once again Love StackOverflow!
in above answer need change pInfo to pm
like this
PackageManager pm = getPackageManager();
try {
ApplicationInfo ai = pm.getApplicationInfo(<packageName here>, 0);
String sourceApk = ai.publicSourceDir;
} catch (NameNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this answer by Seth

Android Facebook SDK

I am working with Android Facebook SDK and wanted to get a friends list. I have created an "AsyncTask" for doing such a thing. I am pasting my doInBackgroundMethod here.
#Override
protected String doInBackground(String... url) {
String jsonResponse;
try {
jsonResponse = Factory.getFacebook().request(Utils.LOGGEDIN_USER_FRIENDS);
} catch (MalformedURLException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
return jsonResponse;
}
Utils Code
public static final String LOGGEDIN_USER_FRIENDS = "me/friends";
The problem I am running in to is that it is returning an empty jsonResponse for the first time the application runs. When I open my app the second time I am getting the JsonResponse. But for the first time however I am getting empty jsonResponse.
Can any one help me out in this regard.
Well it was easy... It was messed up by creating a String variable in a Factory. Later on, the same day I saw that, and called the AsyncTask built in method get which provides the result in the same thread.

Categories

Resources