Запуск пакета на Knopflerfish, встроенного в Android, не работает
Я встраиваю среду Knopflerfish в приложение для Android, чтобы динамически запускать и останавливать пакеты.
Я следовал этому руководству, скачал framework.jar из этой ссылки и добавил ее к своему пути к классам в моем проекте eclipse.
Кроме того, ниже приведен класс Activity, который запускает фреймворк и запускает один пакет:
package com.example.knopflerfish_android;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Dictionary;
import java.util.Hashtable;
import java.util.Map;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.widget.Toast;
import org.knopflerfish.framework.FrameworkFactoryImpl;
import org.osgi.framework.BundleException;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
import org.osgi.service.startlevel.StartLevel;
public class MainActivity extends Activity {
private static final String TAG = "Zaid Log";
private Framework mFramework;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("here!");
Map<String, String> fwprops = new Hashtable<String, String>(); //CHANGED
// add any framework properties to fwprops
fwprops.put("org.osgi.framework.storage", "sdcard/fwdir");
FrameworkFactory ff = new FrameworkFactoryImpl();
mFramework = ff.newFramework(fwprops);
try {
mFramework.init(); //STUCK HERE!!
} catch (BundleException be) {
// framework initialization failed
Log.d(TAG, be.getStackTrace().toString());
Log.d(TAG,"failed to initialize Framework");
}
setInitlevel(1);
installBundle("Bundle_AndroidAPI_1.0.0.201308160327.jar");
startBundle("Bundle_AndroidAPI_1.0.0.201308160327.jar");
// install/start other bundles...
setStartLevel(10);
try {
mFramework.start();
} catch (BundleException be) {
Log.e(TAG, be.toString());
// framework start failed
}
Log.d(TAG, "OSGi framework running, state: " + mFramework.getState());
/* helloServiceReference= context.getServiceReference(HelloService.class.getName());
HelloService helloService =(HelloService)context.getService(helloServiceReference);
System.out.println(helloService.sayHello());*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
private void startBundle(String bundle) {
Log.d(TAG, "starting bundle " + bundle);
InputStream bs;
try {
bs = getAssets().open("bundles/" + bundle);
} catch (IOException e) {
Log.e(TAG, e.toString());
return;
}
long bid = -1;
org.osgi.framework.Bundle[] bl = mFramework.getBundleContext().getBundles();
for (int i = 0; bl != null && i < bl.length; i++) {
if (bundle.equals(bl[i].getLocation())) {
bid = bl[i].getBundleId();
}
}
org.osgi.framework.Bundle b = mFramework.getBundleContext().getBundle(bid);
if (b == null) {
Log.e(TAG, "can't start bundle " + bundle);
return;
}
try {
b.start(org.osgi.framework.Bundle.START_ACTIVATION_POLICY);
Log.d(TAG, "bundle " + b.getSymbolicName() + "/" + b.getBundleId() + "/"
+ b + " started");
Toast.makeText(getApplicationContext(),"bundle " + b.getSymbolicName() + "/" + b.getBundleId() + "/"
+ b + " started" , Toast.LENGTH_SHORT).show();
} catch (BundleException be) {
Log.e(TAG, be.toString());
}
try {
bs.close();
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
private void installBundle(String bundle) {
Log.d(TAG, "installing bundle " + bundle);
Toast.makeText(getApplicationContext(), "installing bundle", Toast.LENGTH_SHORT).show();
InputStream bs;
try {
bs = getAssets().open("bundles/" + bundle);
} catch (IOException e) {
Log.e(TAG, e.toString());
return;
}
try {
mFramework.getBundleContext().installBundle(bundle, bs);
Log.d(TAG, "bundle " + bundle + " installed");
Toast.makeText(getApplicationContext(), "bundle " + bundle + " installed", Toast.LENGTH_SHORT).show();
} catch (BundleException be) {
Log.e(TAG, be.toString());
}
try {
bs.close();
} catch (IOException e) {
Log.e(TAG, e.toString());
}
}
private void setStartLevel(int startLevel) {
ServiceReference sr = mFramework.getBundleContext()
.getServiceReference(StartLevel.class.getName());
if (sr != null) {
StartLevel ss =
(StartLevel)mFramework.getBundleContext().getService(sr);
ss.setStartLevel(startLevel);
mFramework.getBundleContext().ungetService(sr);
} else {
Log.e(TAG, "No start level service " + startLevel);
}
}
private void setInitlevel(int level) {
ServiceReference sr = mFramework.getBundleContext()
.getServiceReference(StartLevel.class.getName());
if (sr != null) {
StartLevel ss =
(StartLevel)mFramework.getBundleContext().getService(sr);
ss.setInitialBundleStartLevel(level);
mFramework.getBundleContext().ungetService(sr);
Log.d(TAG, "initlevel " + level + " set");
} else {
Log.e(TAG, "No start level service " + level);
}
}
}
Как я сказал в своем предыдущем вопросе, в соответствии с @ldx в этом посте:"Патчи, которые я отправил для лучшей поддержки Android / Dalvik в Knopflerfish, были объединены, поэтому исправление и перекомпиляция KF больше не нужны:"
и поэтому я ничего не добавил, предполагая, что моего кода достаточно, как сейчас.
Когда я запускаю приложение для Android, я не получаю никакой ошибки, вместо этого я получаю положительные сообщения на своем LogCat о том, что мой пакет был установлен и запущен. Смотрите мой журнал ниже (я игнорирую первые 2 строки):
08-15 23:32:08.381: E/Trace(22044): error opening trace file: No such file or directory (2)
08-15 23:32:08.381: E/Trace(22044): error opening trace file: No such file or directory (2)
08-15 23:32:09.441: I/System.out(22044): here!
08-15 23:32:10.320: D/dalvikvm(22044): GC_CONCURRENT freed 172K, 10% free 2695K/2984K, paused 73ms+85ms, total 236ms
08-15 23:32:10.720: D/dalvikvm(22044): GC_CONCURRENT freed 324K, 14% free 2816K/3260K, paused 73ms+85ms, total 214ms
08-15 23:32:10.762: D/Zaid Log(22044): initlevel 1 set
08-15 23:32:10.762: D/Zaid Log(22044): installing bundle Bundle_AndroidAPI_1.0.0.201308160327.jar
08-15 23:32:11.060: D/Zaid Log(22044): bundle Bundle_AndroidAPI_1.0.0.201308160327.jar installed
08-15 23:32:11.080: D/Zaid Log(22044): starting bundle Bundle_AndroidAPI_1.0.0.201308160327.jar
08-15 23:32:11.090: D/Zaid Log(22044): bundle Bundle_AndroidAPI/4/BundleImpl[id=4] started
08-15 23:32:11.140: D/Zaid Log(22044): OSGi framework running, state: 32
08-15 23:32:12.012: D/gralloc_goldfish(22044): Emulator without GPU emulation detected.
08-15 23:32:52.941: I/Choreographer(22044): Skipped 47 frames! The application may be doing too much work on its main thread.
Тем не менее, моя связка не началась. Сообщение в методе запуска комплекта появилось бы на LogCat, если бы мой комплект действительно стартовал. Ниже мой метод запуска пакета:
public void start(BundleContext bundleContext) throws Exception {
Activator.context = bundleContext;
System.out.println("Hello World. I am the OSGI_Android_Bundle!");
}
Обратите внимание, что мой пакет был dexified, но все же он не запускается в моем приложении. Где я неправ?
Обновление 1: я подумал, что я должен поменять местами начало фреймворка с запуском пакета. Автор руководства сначала запускает комплекты, но я решил изменить это, потому что имеет смысл сначала запустить фреймворк, поэтому мой обновленный код имеет следующее:
setInitlevel(1);
// install/start other bundles...
setStartLevel(10);
try {
mFramework.start();
} catch (BundleException be) {
Log.e(TAG, be.toString());
// framework start failed
}
Log.d(TAG, "OSGi framework running, state: " + mFramework.getState());
installBundle("Bundle-Test_1.0.0.201308160536.jar");
startBundle("Bundle-Test_1.0.0.201308160536.jar");
Теперь журнал не показывает мне, что мой пакет запущен, как раньше, а скорее говорит, что среда исполнения не поддерживается. Смотрите обновленный LogCat ниже:
08-16 01:43:06.821: I/System.out(22737): here!
08-16 01:43:08.080: D/dalvikvm(22737): GC_CONCURRENT freed 191K, 11% free 2656K/2968K, paused 35ms+18ms, total 155ms
08-16 01:43:09.010: D/dalvikvm(22737): GC_CONCURRENT freed 276K, 13% free 2806K/3200K, paused 25ms+15ms, total 110ms
08-16 01:43:09.238: D/Zaid Log(22737): initlevel 1 set
08-16 01:43:09.300: D/Zaid Log(22737): OSGi framework running, state: 32
08-16 01:43:09.300: D/Zaid Log(22737): installing bundle Bundle-Test_1.0.0.201308160536.jar
08-16 01:43:09.530: D/Zaid Log(22737): bundle Bundle-Test_1.0.0.201308160536.jar installed
08-16 01:43:09.540: D/Zaid Log(22737): starting bundle Bundle-Test_1.0.0.201308160536.jar
08-16 01:43:09.550: E/Zaid Log(22737): org.osgi.framework.BundleException: Bundle#5, unable to resolve: Execution environment 'J2SE-1.5' is not supported
08-16 01:43:10.740: D/gralloc_goldfish(22737): Emulator without GPU emulation detected.
Обновление 2: я удалил эту строку из своего МАНИФЕСТА пакета после ответа Нила ниже,
Bundle-RequiredExecutionEnvironment: J2SE-1.5
но это привело к следующей ошибке:
org.osgi.framework.BundleException: Bundle#6 start failed
Возможно, я не должен был менять порядок запуска фреймворка и запуска пакета. Ниже мой обновленный LogCat.
08-16 17:02:33.855: E/Trace(28805): error opening trace file: No such file or directory (2)
08-16 17:02:35.111: I/System.out(28805): here!
08-16 17:02:35.591: D/dalvikvm(28805): GC_CONCURRENT freed 199K, 11% free 2679K/2996K, paused 76ms+93ms, total 246ms
08-16 17:02:36.153: D/dalvikvm(28805): GC_CONCURRENT freed 268K, 13% free 2814K/3200K, paused 77ms+141ms, total 297ms
08-16 17:02:36.451: D/Zaid Log(28805): initlevel 1 set
08-16 17:02:36.531: D/Zaid Log(28805): OSGi framework running, state: 32
08-16 17:02:36.531: D/Zaid Log(28805): installing bundle Bundle-Test_1.0.0.201308161323.jar
08-16 17:02:36.611: D/Zaid Log(28805): bundle Bundle-Test_1.0.0.201308161323.jar installed
08-16 17:02:36.631: D/Zaid Log(28805): starting bundle Bundle-Test_1.0.0.201308161323.jar
08-16 17:02:36.646: E/Zaid Log(28805): org.osgi.framework.BundleException: Bundle#6 start failed
08-16 17:02:36.646: E/Zaid Log(28805): More:Bundle#6 start failed
08-16 17:02:36.681: W/System.err(28805): org.osgi.framework.BundleException: Bundle#6 start failed
08-16 17:02:36.681: W/System.err(28805): at org.knopflerfish.framework.BundleImpl.start0(BundleImpl.java:421)
08-16 17:02:36.681: W/System.err(28805): at org.knopflerfish.framework.BundleThread.run(BundleThread.java:145)
08-16 17:02:36.681: W/System.err(28805): Caused by: java.lang.ClassNotFoundException: bundle_test.Activator
08-16 17:02:36.681: W/System.err(28805): at org.knopflerfish.framework.BundleClassLoader.findClass(BundleClassLoader.java:218)
08-16 17:02:36.681: W/System.err(28805): at org.knopflerfish.framework.BundleClassLoader.loadClass(BundleClassLoader.java:347)
08-16 17:02:36.681: W/System.err(28805): at java.lang.ClassLoader.loadClass(ClassLoader.java:461)
08-16 17:02:36.694: W/System.err(28805): at org.knopflerfish.framework.BundleImpl.start0(BundleImpl.java:382)
08-16 17:02:36.694: W/System.err(28805): ... 1 more
08-16 17:02:37.282: I/Choreographer(28805): Skipped 34 frames! The application may be doing too much work on its main thread.
08-16 17:02:37.551: D/gralloc_goldfish(28805): Emulator without GPU emulation detected.
1 ответ
Я исправлю только ошибку в вашем обновленном вопросе, поскольку кажется, что первая проблема была исправлена (пожалуйста, подтвердите).
Ошибка означает, что в комплект входит следующее требование:
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Другими словами, пакет утверждает, что он требует стандартную Java 5 или выше. Это известно как среда выполнения или EE. Обычно OSGi Framework определяет тип среды выполнения Java, на которой вы его запустили, и публикует набор EE, соответствующих этому. Например, если вы работаете на стандартной Java 5, платформа публикует EE с именем J2SE-1.5
, J2SE-1.4
и т.д. вплоть до JRE-1.0
потому что Java 5 обратно совместима со всеми этими версиями. Однако, если у вас есть пакет, который утверждает Bundle-RequiredExecutionEnvironment: JavaSE-1.6
и вы пытаетесь запустить его на Java 5, тогда он не сможет решить.
Теперь вы пытаетесь запустить на Android, который не является стандартным Java. Хотя и похожи на стандартную Java, многие части стандартных API JRE были удалены. Поэтому пакет, который требует стандартную Java 5, не должен разрешаться на Android, потому что он может пытаться вызвать API, которые не существуют на этой платформе.
Вероятно, самое простое, что вам нужно сделать, это удалить Bundle-RequiredExecutionEnvironment
заголовок из пакета, который не разрешается. Это позволит установить и разрешить его, но, конечно, может позже произойти сбой с ошибками во время выполнения, если ему действительно потребуется вызывать методы из стандартного JRE, которых нет в Android.