Я встраиваю фреймворк Knopflerfish в приложение для Android, чтобы динамически запускать и останавливать пакеты.
Я следил за этим учебным курсом, загруженным фреймворком. jar из ссылки this и добавил ее в мой путь к классам в моем проекте 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!");
}
Обратите внимание, что мой пакет был дексифицирован, но все же он не запускается в моем приложении. Где я ошибся?
Обновление 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: я удалил эту строку из МАНИФЕСТА пакета после ответа @ Neil ниже,
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.