السلام عليكم .
اليوم عندي تحدي كبير جدا وانا أريد مساعدتكم .
لدي برنامج اندرويد ، مغلق المصدر ولكن صاحب البرنامج إختار عدم إكمال تطوير البرنامج.
البرنامج فية مشكلة عند استدعاء البيانات حيث يبدو أن المبرمج لم يقم بإغلاق احد الإستدعاءات . حيث عند مراقبة ال CATLOG يظهر عندي رسالة خطا مفادها التالي :
11-14 15:42:26.420 W/SQLiteConnectionPool(15763): A SQLiteConnection object for database '/data/data/com.bookscars.src.v65/databases/AppDbStoreroot7' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
يسئل البعض (كيف سوف تعدل على برنامج مغلق المصدر؟)
طبعا عن طريق الهنسة العكسية ولا مشكلة بذلك .
الان قمت بعمل Decompile للتطبيق وحللت الشيفرة المصدرية . وبحثت عن الكلاس الذي يقوم بطلب قاعدة البيانات AppDbStoreroot7 فوجدت هذا الكلاس :
package com.studio.sm.root.utility;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.util.Iterator;
import java.util.Vector;
import org.json.JSONArray;
import org.json.JSONObject;
public class RootLogsStorage
{
private static final String DATABASE_NAME = "AppDbStoreroot7";
private static final int DATABASE_VERSION = 1;
public static final String TABLE_BOOKS = "books";
public static final String TABLE_CARS = "cars";
private static final String TAG = "RootLogsStorage";
private DatabaseHelper DBHelper;
private final Context context;
private SQLiteDatabase db;
private RootLogsStorage(Context paramContext)
{
this.context = paramContext;
this.DBHelper = new DatabaseHelper(this.context, null);
}
public static void clearStorage(Context paramContext)
{
RootLogsStorage localRootLogsStorage = getWritable(paramContext);
localRootLogsStorage.emptyLogTable("books");
localRootLogsStorage.emptyLogTable("cars");
localRootLogsStorage.close();
}
private boolean emptyLogTable(String paramString)
{
return this.db.delete(paramString, null, null) > 0;
}
private static String getCreateStringFor(String paramString)
{
return "create table " + paramString + " (_id integer primary key autoincrement, " + "contents text not null);";
}
private Cursor getCursorOf(String paramString)
{
Cursor localCursor = this.db.query(paramString, new String[] { "_id", "contents" }, null, null, null, null, null);
if ((localCursor == null) || (localCursor.getCount() <= 0) || (!localCursor.moveToFirst()))
{
if (localCursor != null) {
localCursor.close();
}
localCursor = null;
}
return localCursor;
}
public static RootLogsStorage getReadable(Context paramContext)
{
return new RootLogsStorage(paramContext).openToRead();
}
public static RootLogsStorage getWritable(Context paramContext)
{
return new RootLogsStorage(paramContext).openToWrite();
}
private RootLogsStorage openToRead()
throws SQLException
{
this.db = this.DBHelper.getReadableDatabase();
return this;
}
private RootLogsStorage openToWrite()
throws SQLException
{
this.db = this.DBHelper.getWritableDatabase();
return this;
}
public void close()
{
this.db.close();
this.DBHelper.close();
}
public JSONArray getLogContentsOf(String paramString)
throws Exception
{
JSONArray localJSONArray = new JSONArray();
Cursor localCursor = getCursorOf(paramString);
if (localCursor == null) {
return localJSONArray;
}
while (!localCursor.isAfterLast())
{
localJSONArray.put(new JSONObject(localCursor.getString(1)));
localCursor.moveToNext();
}
localCursor.close();
return localJSONArray;
}
public void insertLogs(String paramString, Vector<String> paramVector)
{
Log.e("RootLogsStorage INSERT", paramString + "/" + paramVector.size());
Iterator localIterator = paramVector.iterator();
for (;;)
{
if (!localIterator.hasNext()) {
return;
}
String str = (String)localIterator.next();
ContentValues localContentValues = new ContentValues();
localContentValues.put("contents", str);
this.db.insert(paramString, null, localContentValues);
}
}
private static class DatabaseHelper
extends SQLiteOpenHelper
{
private DatabaseHelper(Context paramContext)
{
super("AppDbStoreroot7", null, 1);
}
public void onCreate(SQLiteDatabase paramSQLiteDatabase)
{
paramSQLiteDatabase.execSQL(RootLogsStorage.getCreateStringFor("books"));
paramSQLiteDatabase.execSQL(RootLogsStorage.getCreateStringFor("cars"));
}
public void onUpgrade(SQLiteDatabase paramSQLiteDatabase, int paramInt1, int paramInt2) {}
}
}
وبحكم عدم خبرتي الكبيرة بالجافا ، اتمنى إرشادي إلى المكان الذي يجب أن أضيف فية تعليمة الإغلاق.. وحبذا لو كان الامر عن طريق النخ واللصق من الكود حيث التعديل يكون أسهل في البيات كود ..
حيث انه يمكنني ان أرى الكود التالي ضمن الكلاس ..
public void close()
{
this.db.close();
this.DBHelper.close();
}
المرحلة التانية سوف أريكم كيف أقوم بالتعديل حيث أن هذا بحد ذاته تحدي كبير بالتعديل على البايت كود الخاص بالاندرويد .