License Verification Library in Wallpaper - android

I am currently trying to implement Google's LVL into my wallpaper but seem to have run into an issue with an exception I am not familiar with. I found this Question which helped me greatly, LVL licensing in a Live Wallpaper?. One of the suggestions is to place code within the Engine and I opted to place it in the Class above. The code seems to compile fine but on run time I get an exception, apparently for my Public Key.
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to create service <my package>.MyWallpaper: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2076)
at android.app.ActivityThread.access$2500(ActivityThread.java:123)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:993)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3835)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:847)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:605)
at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.IllegalArgumentException: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at com.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:121)
at com.android.vending.licensing.LicenseChecker.<init>(LicenseChecker.java:92)
at com.metastable.epicvis.vis1.ScopeVisualizer.onCreate(ScopeVisualizer.java:41)
at android.app.ActivityThread.handleCreateService(ActivityThread.java:2066)
... 10 more
Caused by: java.security.spec.InvalidKeySpecException: java.io.IOException: corrupted stream - out of bounds length found
at org.bouncycastle.jce.provider.JDKKeyFactory.engineGeneratePublic(JDKKeyFactory.java:92)
at org.bouncycastle.jce.provider.JDKKeyFactory$RSA.engineGeneratePublic(JDKKeyFactory.java:396)
at java.security.KeyFactory.generatePublic(KeyFactory.java:177)
at com.android.vending.licensing.LicenseChecker.generatePublicKey(LicenseChecker.java:112)
... 13 more
Here is the code that I use:
public class MyWallpaper extends WallpaperService implements LicenseCheckerCallback {
private LicenseChecker mChecker;
private static final String BASE64_PUBLIC_KEY = "My public key from google";
private byte[] salt = new byte[] {<20 random int>};
private String deviceId;
private AESObfuscator aes;
#Override
public void onCreate() {
super.onCreate();
deviceId = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
aes = new AESObfuscator(salt, getPackageName(), deviceId);
mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, aes), BASE64_PUBLIC_KEY);
mChecker.checkAccess(this);
}
#Override
public void onDestroy() {
super.onDestroy();
mChecker.onDestroy();
}
#Override
public Engine onCreateEngine() {
return new VisualizerEngine();
}
class MyEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener {
<Unrelevant code removed>
}
#Override
public void allow() {
Toast.makeText(this, "Allowed", Toast.LENGTH_SHORT);
}
#Override
public void dontAllow() {
Toast.makeText(this, "Not Allowed", Toast.LENGTH_SHORT);
}
#Override
public void applicationError(ApplicationErrorCode errorCode) {
// TODO Auto-generated method stub
}
}
Is there a certain way I should format my public key or is it something entirely different?
The exception comes from : mChecker = new LicenseChecker(this, new ServerManagedPolicy(this, aes), BASE64_PUBLIC_KEY);
Any advice would be greatly appreciated.

I have since figured out the issue, apparently I'm terrible and copy and pasting. In stead of click dragging and selecting my key, which I did many times and continued to fail, I simply triple clicked and it copied properly. Heh.

Related

Android PrintServer crashes when pressing print button while rendering preview

I try to implement my own printer (means print server) based on the Android PrintServer API. This print server provides a static single printer which tasks is to upload the print job to a web page via http upload.
I am using Marshmallow on a Sony Z2. And for testing I use the email application and "printing" from the submenu.
In principle I managed all the business logic already and it works, so at least I used the right approach. But when I press the "print" button (with the printer logo) in the Android print dialog to fast, the whole print server crashes. If I wait until the dialog rendered all the preview and then press the button, everything is fine.
I dont know if the problem is clear therefore I made a small movie (1,8MB), which you can find here:
https://c.geniusbytes.com/index.php/s/leJrSGRlxBSSCux
To reduce the problem I removed all the transfer code and arrived at the most minimal version which still causes the crash, see below.
Can somebody see what is the problem? On my mobile there is also the PDF-writer PrintServer (Sony!?). This does not crash with the same procedure. Instead the "print" behavior, which is the selection of the destination to store the PDF, waits until the preview is rendered and then pops up.
It is important to mention that one need a larger document to print. Otherwise the preview is rendered to fast for causing the crash by pressing the print button.
Here is the code for the PrintServer implementation:
public class UploadPrintService extends PrintService {
private static final String LOG_TAG = "UploadPrintService";
////////////////////////////////////////////////
//
// service methods
//
/////////////////////////////////////////////////
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Override
protected void onConnected() {
Log.i(LOG_TAG, "#onConnected()");
}
#Override
protected void onDisconnected() {
Log.i(LOG_TAG, "#onDisconnected()");
}
#Override
protected PrinterDiscoverySession onCreatePrinterDiscoverySession() {
Log.i(LOG_TAG, "#onCreatePrinterDiscoverySession()");
return new UploadPrintDiscoverySession(this);
}
#Override
protected void onRequestCancelPrintJob(PrintJob printJob) {
// standard cancel
if ((printJob.isStarted() && (!printJob.isCancelled()))) {
printJob.cancel();
}
}
#Override
protected void onPrintJobQueued(final PrintJob printJob) {
Log.i(LOG_TAG, "#onPrintJobQueued");
printJob.start();
}
}
And the PrinterDiscoverySession is implemented in a way, such that it always returns the same printer. See here:
public class UploadPrintDiscoverySession extends PrinterDiscoverySession {
private static final String LOG_TAG = UploadPrintDiscoverySession.class.getSimpleName();
private PrintService printService = null;
private static final String PRINTER_ID = "my.uploadprinter.id";
public UploadPrintDiscoverySession(PrintService printService) {
super();
Log.i(LOG_TAG, "new discovery session!");
this.printService = printService;
}
#Override
public void onStartPrinterDiscovery(List<PrinterId> list) {
Log.i(LOG_TAG, "#onStartPrinterDiscovery");
addUploadPrinter();
}
#Override
public void onStopPrinterDiscovery() {
Log.i(LOG_TAG, "#onStopPrinterDiscovery");
}
#Override
public void onValidatePrinters(List<PrinterId> list) {
Log.i(LOG_TAG, "#onValidatePrinters");
addUploadPrinter();
}
#Override
public void onStartPrinterStateTracking(PrinterId printerId) {
Log.i(LOG_TAG, "#onStartPrinterStateTracking");
addUploadPrinter();
}
#Override
public void onStopPrinterStateTracking(PrinterId printerId) {
Log.i(LOG_TAG, "#onStopPrinterStateTracking");
}
#Override
public void onDestroy() {
Log.i(LOG_TAG, "#onDestroy");
}
private void addUploadPrinter() {
Log.i(LOG_TAG, "#addUploadPrinter");
PrinterId uploadPrinterId = printService.generatePrinterId(PRINTER_ID);
PrinterInfo.Builder printerInfoBuilder = new PrinterInfo.Builder(uploadPrinterId,
"Mighty Printer", PrinterInfo.STATUS_IDLE);
PrinterCapabilitiesInfo.Builder capBuilder =
new PrinterCapabilitiesInfo.Builder(uploadPrinterId);
capBuilder.addMediaSize(PrintAttributes.MediaSize.ISO_A4, true);
capBuilder.addMediaSize(PrintAttributes.MediaSize.ISO_A3, false);
capBuilder.addResolution(new PrintAttributes.Resolution(
"Default", "default resolution", 600, 600), true);
capBuilder.setColorModes(PrintAttributes.COLOR_MODE_COLOR
| PrintAttributes.COLOR_MODE_MONOCHROME,
PrintAttributes.COLOR_MODE_COLOR);
printerInfoBuilder.setCapabilities(capBuilder.build());
Log.i(LOG_TAG, "add *the* printer to the list...");
List<PrinterInfo> discoveredPrinterList = new ArrayList<PrinterInfo>();
discoveredPrinterList.add(printerInfoBuilder.build());
this.addPrinters(discoveredPrinterList);
}
}
Thanks for the Logcat-hint, I was already wondering why I see no error but when I disabled the filter which was activated by default, then I see the following error:
09-05 20:06:05.523 27568-27568/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.android.printspooler, PID: 27568
java.lang.IllegalArgumentException: end cannot be less than zero.
at android.print.PageRange.<init>(PageRange.java:50)
at com.android.printspooler.util.PageRangeUtils.asAbsoluteRange(PageRangeUtils.java:199)
at com.android.printspooler.ui.PrintActivity$DocumentTransformer.computePagesToShred(PrintActivity.java:2620)
at com.android.printspooler.ui.PrintActivity$DocumentTransformer.<init>(PrintActivity.java:2496)
at com.android.printspooler.ui.PrintActivity.transformDocumentAndFinish(PrintActivity.java:1733)
at com.android.printspooler.ui.PrintActivity.requestCreatePdfFileOrFinish(PrintActivity.java:967)
at com.android.printspooler.ui.PrintActivity.onUpdateCompleted(PrintActivity.java:492)
at com.android.printspooler.model.RemotePrintDocument.notifyUpdateCompleted(RemotePrintDocument.java:385)
at com.android.printspooler.model.RemotePrintDocument.access$900(RemotePrintDocument.java:55)
at com.android.printspooler.model.RemotePrintDocument$1.onDone(RemotePrintDocument.java:117)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand.handleOnWriteFinished(RemotePrintDocument.java:1000)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand.access$2200(RemotePrintDocument.java:867)
at com.android.printspooler.model.RemotePrintDocument$WriteCommand$WriteHandler.handleMessage(RemotePrintDocument.java:1061)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:234)
at android.app.ActivityThread.main(ActivityThread.java:5526)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
0
And some lines later there I found:
09-05 20:06:06.956 1005-3292/? I/WindowState: WIN DEATH: Window{ff8499c u0 com.android.printspooler/com.android.printspooler.ui.PrintActivity}
09-05 20:06:06.956 1005-3325/? W/UserState: Not stopping printer state tracking - session destroyed
09-05 20:06:06.956 1005-3924/? D/GraphicsStats: Buffer count: 7
09-05 20:06:06.957 1005-1005/? D/RemotePrintSpooler: Error clearing print spooler client
android.os.DeadObjectException
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:503)
at android.print.IPrintSpooler$Stub$Proxy.setClient(IPrintSpooler.java:358)
at com.android.server.print.RemotePrintSpooler.clearClientLocked(RemotePrintSpooler.java:424)
at com.android.server.print.RemotePrintSpooler.access$400(RemotePrintSpooler.java:53)
at com.android.server.print.RemotePrintSpooler$MyServiceConnection.onServiceDisconnected(RemotePrintSpooler.java:456)
at android.app.LoadedApk$ServiceDispatcher.doDeath(LoadedApk.java:1232)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run(LoadedApk.java:1246)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:234)
at com.android.server.SystemServer.run(SystemServer.java:302)
at com.android.server.SystemServer.main(SystemServer.java:174)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onStopPrinterStateTracking
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onStopPrinterDiscovery
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintDiscoverySession: #onDestroy
09-05 20:06:06.958 26358-26358/com.geniusbytes.uploadprintservice I/UploadPrintService: #onDisconnected()
09-05 20:06:07.006 1005-3886/? I/ActivityManager: Process com.android.printspooler (pid 27568) has died
09-05 20:06:07.006 1005-3886/? W/ActivityManager: Scheduling restart of crashed service com.android.printspooler/.model.PrintSpoolerService in 1000ms
09-05 20:06:07.188 1005-1237/? W/AppOps: Finishing op nesting under-run: uid 1000 pkg android code 24 time=1462541465446 duration=2311 nesting=0
09-05 20:06:08.024 1005-1185/? I/ActivityManager: Start proc 5263:com.android.printspooler/u0a159 for service com.android.printspooler/.model.PrintSpoolerService
09-05 20:06:09.953 391-3149/? D/audio_hw_primary: out_standby: enter: stream (0xb5bf7240) usecase(0: deep-buffer-playback)

pusher-java-client eventQueue inside onCreate

Hi im using pusher for notifications, after some test i keep having troubles, now i have this message when i intent to load a task.
02-08 13:43:56.751 20712-21208/package E/AndroidRuntime: FATAL EXCEPTION: pusher-java-client eventQueue
java.lang.NoClassDefFoundError: com.pusher.client.connection.websocket.WebSocketClientWrapper
at com.pusher.client.util.Factory.newWebSocketClientWrapper(Factory.java:67)
at com.pusher.client.connection.websocket.WebSocketConnection$1.run(WebSocketConnection.java:63)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573)
at java.lang.Thread.run(Thread.java:841)
this is how i call pusher connection in onCreate
runOnUiThread(new Runnable() {
#Override
public void run() {
// Create a new Pusher instance
Pusher pusher = new Pusher("KEY");
pusher.connect(new ConnectionEventListener() {
#Override
public void onConnectionStateChange(ConnectionStateChange change) {
System.out.println("State changed to " + change.getCurrentState() +
" from " + change.getPreviousState());
}
#Override
public void onError(String message, String code, Exception e) {
System.out.println("There was a problem connecting!");
}
}, ConnectionState.ALL);
Channel channel = pusher.subscribe("my-channel");
channel.bind("my-event", new SubscriptionEventListener() {
#Override
public void onEvent(String channel, String event, String data) {
System.out.println("Received event with data: " + data);
}
});
pusher.disconnect();
pusher.connect();
logger.info("Hubo un problema al conectarse");
}
});
Im stuck here, i don´t know if im implementing in a bad way the Thread, some tips will be helpful, thanks!
The reason behind this error is the 64K limit in android VM.
To fix it U should download this jar:
http://central.maven.org/maven2/com/pusher/pusher-java-client/1.2.1/pusher-java-client-1.2.1-jar-with-dependencies.jar
Add it and remove any existing java-client-* from your project dependency.
Also remove any com.google.gson from your gradle.build file.
Finally, enable multidex in your project:
https://developer.android.com/studio/build/multidex.html
that worked for me.

Error when displaying the map using Skobbler in Android

I want to integrate a map in my android application. But I'm just starting form the basics and I'm already encountering a crash/error.
I just copied some codes from the demo project but still no luck.
Logcat :
08-14 16:19:55.703: E/AndroidRuntime(30065): FATAL EXCEPTION: GLThread 787
08-14 16:19:55.703: E/AndroidRuntime(30065): java.lang.NullPointerException
08-14 16:19:55.703: E/AndroidRuntime(30065): at com.skobbler.ngx.map.MapRenderer.onSurfaceCreated(SourceFile:487)
08-14 16:19:55.703: E/AndroidRuntime(30065): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1509)
08-14 16:19:55.703: E/AndroidRuntime(30065): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)
I researched already but I haven;t found any solution yet.
Please help.
Here's my code:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SKLogging.enableLogs(true);
File externalDir = getExternalFilesDir(null);
if (externalDir != null) {`enter code here`
mapresDirPath = externalDir + "/SKMaps/";
} else {
mapresDirPath = getFilesDir() + "/SKMaps/";
}
if (!new File(mapresDirPath).exists()) {
new SKPrepareMapTextureThread(this, mapresDirPath, "SKMaps.zip", this).start();
copyOtherResources();
prepareMapCreatorFile();
} else {
Toast.makeText(MainActivity.this, "Map resources copied in a previous run", Toast.LENGTH_SHORT).show();
prepareMapCreatorFile();
initializeLibrary();
finish();
startActivity(new Intent(MainActivity.this, MapActivity.class));
}
}
private void initializeLibrary() {
SKMapsInitSettings initSettings = new SKMapsInitSettings();
initSettings.setMapResourcesPaths(mapresDirPath, new SKMapViewStyle(mapresDirPath + "daystyle/", "daystyle.json"));
final SKAdvisorSettings advisorSettings = initSettings.getAdvisorSettings();
advisorSettings.setLanguage("en");
advisorSettings.setAdvisorVoice("en");
advisorSettings.setPlayInitialAdvice(true);
advisorSettings.setPlayAfterTurnInformalAdvice(true);
advisorSettings.setPlayInitialVoiceNoRouteAdvice(true);
initSettings.setAdvisorSettings(advisorSettings);
SKVersioningManager.getInstance().setMapUpdateListener(this);
SKMaps.getInstance().initializeSKMaps(this, initSettings, API_KEY);
}
#Override
public void onMapTexturesPrepared(boolean prepared) {
initializeLibrary();
runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(MainActivity.this, "Map resources were copied", Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(MainActivity.this, MapActivity.class));
}
});
}
MapActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map);
SKMapViewHolder mapViewHolder = (SKMapViewHolder) findViewById(R.id.map_surface_holder);
mapView = mapViewHolder.getMapSurfaceView();
mapView.getMapSettings().setMapPanningEnabled(true);
mapView.getMapSettings().setMapZoomingEnabled(true);
mapView.getMapSettings().setInertiaPanningEnabled(true);
SKVersioningManager.getInstance().setMapUpdateListener(this);
}
I had the same problem, and I posted an answer on their support forum :
Hi,
Implementing Skobbler in my android app, I stucked half an hour with a crash I couldn't understand.
Following the DemoApp for the initialization part, I kept crashing just before map was displayed with error:
java.lang.NullPointerException
at com.skobbler.ngx.map.MapRenderer.onSurfaceCreated( SourceFile:487)
at android.opengl.GLSurfaceView$GLThread.guardedRun(G LSurfaceView.java:1509)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfac eView.java:1248)
As the error wasn't self explanatory at all, I investigated file MapRenderer from package com.skobbler.ngx.map, and found
that I was crashing because I didn't implement a map listener (this.s, in line below), which classname was trying to be displayed on log.
public final void onSurfaceCreated(GL10 arg1, EGLConfig paramEGLConfig)
{
SKLogging.writeLog("MapRenderer", "onSurfaceCreated before LOCK ", 2);
synchronized (V) {
SKLogging.writeLog("MapRenderer", "onSurfaceCreated" + this.s.getClass().getName(), 2); // <== Line 487
You might have forgot to check non-nullity of this.s before logging it, and as it wasn't described as mandatory in your doc to
implement this listener,I think you should correct that, or otherwise precise it in documentation.
http://forum.skobbler.com/showthread.php/6554-Android-Resolution-for-NullPointerException-onSurfaceCreated(SourceFile-487)?p=17601#post17601
Hope that helps !
tl:dr :
SKMapSurfaceView mapView = mapViewContainer.getMapSurfaceView();
mapView.setMapSurfaceListener(new SKMapSurfaceListener() {...});

RuntimeException on Xperia-devices when using ZXing

I have an application uploaded to Google Play. The app is supposed to scan a QR-code from a pole to register a visit. It works on all devices but Sony XPERIA models. In Google Play Developer Console I get a lot of one particular crash:
java.lang.RuntimeException: autoFocus failed
at android.hardware.Camera.native_autoFocus(Native Method)
at android.hardware.Camera.autoFocus(Camera.java:975)
at me.dm7.barcodescanner.core.CameraPreview$1.run(CameraPreview.java:196)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:213)
at android.app.ActivityThread.main(ActivityThread.java:5225)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:741)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557)
at dalvik.system.NativeStart.main(Native Method)
The only place I call the camera is is here:
public class ScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
private ZXingScannerView m_ScannerView;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
m_ScannerView = new ZXingScannerView(this);
setContentView(m_ScannerView);
}
#Override
public void onResume() {
super.onResume();
m_ScannerView.setResultHandler(ScannerActivity.this);
m_ScannerView.startCamera();
}
#Override
public void onPause() {
super.onPause();
m_ScannerView.stopCamera();
}
As far as I can tell, this is a bug in ZXing. You can implement a workaround by replacing ZXingSurfaceView:AutoFocus with an implementation that catches the exception. (You'll also have to replace a few other files if you go this route, or re-compile ZXing on your own). This doesn't resolve the root cause, though.
This bug was fixed in ZXing on July 29 2015, so updating to the latest version is probably easier.
public void AutoFocus()
{
if (camera != null)
{
if (!tokenSource.IsCancellationRequested)
{
global::Android.Util.Log.Debug("ZXING", "AutoFocus Requested");
try
{
camera.AutoFocus(this);
}
catch (RuntimeException ex)
{
Console.WriteLine("ZXING: Warning: Caught RuntimeException during AutoFocus.");
}
}
}
}

Android WebView No permission to modify given thread, which permission should I declare?

crash log:
java.lang.SecurityException: No permission to modify given thread
android.os.Process.setThreadPriority(Native Method)
android.webkit.WebViewCore$WebCoreThread$1.handleMessage(WebViewCore.java:764)
android.os.Handler.dispatchMessage(Handler.java:99)
android.os.Looper.loop(Looper.java:137)
android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:829)
java.lang.Thread.run(Thread.java:856)
which permission should I declare?
http://developer.android.com/reference/android/Manifest.permission.html
edit:
I found a similar problem in WebView java.lang.SecurityException: No permission to modify given thread
The Answer say "It's cyanogen's fault."
However, in the thread http://code.google.com/p/cyanogenmod/issues/detail?id=5656&thanks=5656&ts=1341224425,cm menbers seem to deny it's CM's bug
Above all, my question is:
How to fix it from my app?
which permission should I declare?
There is no relevant permission for this AFAIK. Unfortunately, the implementation of setThreadPriority() is in native code, which makes it difficult for me to figure out what is going on.
cm menbers seem to deny it's CM's bug
No, they do not. Nobody has posted evidence that it is a problem in CM9 or higher, which is why they marked the issue as stale. If you are seeing this on CM9 or higher, I suggest that you update the issue. If you are seeing this on standard Android, please create a sample project that can reproduce the error.
How to fix it from my app?
You don't, in all likelihood. You could try running some experiments on your WebView, to see if there is some specific content that triggers this exception, and try to modify or eliminate that content.
I get dozens of crash log caused by this exception from my app (which depends on webview heavily), involved ROM version are 4.0.4 and 4.0.3.
It seems that there is no normal way to fix it, so i tried following hacking approach.
code snipet on 4.0.4:
private static Handler sWebCoreHandler;
// Class for providing Handler creation inside the WebCore thread.
private static class WebCoreThread implements Runnable {
// Message id for initializing a new WebViewCore.
private static final int INITIALIZE = 0;
private static final int REDUCE_PRIORITY = 1;
private static final int RESUME_PRIORITY = 2;
public void run() {
Looper.prepare();
Assert.assertNull(sWebCoreHandler);
synchronized (WebViewCore.class) {
sWebCoreHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// ...
// Process.setPriority(...)
}
};
// ...
}
// ...
}
}
I think this exception is thrown from sWebCoreHandler.handleMessage(), if we can wrap try/catch on handleMessage(), the problem could be fixed.
Handler class has four members:
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
IMessenger mMessenger;
mQueue is set as mLooper.mQueue, mCallback is null in sWebCoreHandler, so we just need to set mLooper and mMessenger with values in sWebCoreHandler.
static Handler sProxyHandler = null;
static void tryTweakWebCoreHandler() {
// 4.0.3/4.0.4 rom
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) {
tweakWebCoreHandle();
}
}
static private void tweakWebCoreHandle() {
if (sProxyHandler != null)
return;
try {
Field f = Class.forName("android.webkit.WebViewCore").getDeclaredField("sWebCoreHandler");
f.setAccessible(true);
Object h = f.get(null);
Object mMessenger = null;
Method m = Handler.class.getDeclaredMethod("getIMessenger", (Class<?>[])null);
m.setAccessible(true);
mMessenger = m.invoke(h, (Object[])null);
sProxyHandler = new WebCoreProxyHandler((Handler)h);
if (mMessenger != null) {
Field f1 = Handler.class.getDeclaredField("mMessenger");
f1.setAccessible(true);
f1.set(sProxyHandler, mMessenger);
}
f.set(null, sProxyHandler);
// Log.w(TAG, "sWebCoreHandler: " + h);
} catch (Throwable e) {
Log.w(TAG, "exception: " + e);
}
if (sProxyHandler == null)
sProxyHandler = new Handler();
}
static class WebCoreProxyHandler extends Handler {
final Handler handler;
public WebCoreProxyHandler(Handler handler) {
super(handler.getLooper());
this.handler = handler;
}
public void handleMessage(Message msg) {
// Log.w("WebCoreProxyHandler", "handle msg: " + msg.what);
try {
handler.handleMessage(msg);
} catch (Throwable tr) {
Log.w("WebCoreProxyHandler", "exception: " + tr);
}
}
}
Remain problem is when to invoke tryTweakWebCoreHandler(). I tried to invoke it after a WebView instance is created and tested on some devices, WebCoreProxyHandler.handleMessage() can be called.
Note: i just made some simple test, i'm not sure this problem is resolved as the origin exception can not be reproduced reliably.
If you decide to try this approach, please do enough test.

Categories

Resources