symbian 2nd如何繞過程序管理器的限制

symbian 2nd如何繞過程序管理器的限制

 

北京理工大學  20981  陳罡

 

symbian開發中我們經常會用到手機系統自帶的程序管理這個軟件。 這個軟件的功能在於它會忠實地把程序的安裝操作記錄下來,在刪除 程序的時候它也會忠實地把程序給刪除。這種做法對於symbian來說, 無疑是最好的選用第三方軟件的選擇,既可以安裝到手機上,又可以 無條件的將軟件卸載掉。

 

但是這個所謂的程序管理,也有很多弊端。例如,每次都需要把程序 的安裝包拷貝到手機存儲上去,這樣安裝包一旦大於2M,對於多數s60 手機來說,這個程序極有可能引起手機內存不足,請關閉一些程序這樣 的錯誤提示,最終導致安裝失敗。再有就是程序的升級,有的時候不需要 整個將sis包重新安裝一遍,只是覆蓋掉幾個dll文件即可,但是很多情況 下,開發者都是選擇將程序全部重新安裝一遍,如果打包的時候升級過sis 包的版本,那麼將在程序管理中看到多個安裝記錄。另外目前很多公司 都在尋找手機程序預裝的方法,其實從其本質來說就是希望程序安裝到 用戶的手機上以後,無法被用戶使用普通的程序管理程序卸載。

 

在這裏我要討論一種方式,可以繞過程序管理器的限制,在程序管理 裏面沒有記錄,也無法把程序從程序管理器裏面卸載,這種方式雖然比較 有效,但是程序的卸載操作就需要使用其它的單獨的卸載程序才能卸載了。

繞過程序管理器的方法其實很簡單,自己編寫一個程序管理器即可。很多 朋友會想編寫一個程序管理器多麼多麼的複雜,需要熟悉sis文件格式之類 的內容。其實一點也不復雜,sis本身就是s60自帶的程序管理器支持的文件 格式,只有nokia的程序管理器才能夠識別。既然我們自己編寫程序管理器 的話,就不必拘泥於sis格式了。自己的程序可以讀取的文件格式就可以自己 說得算了。

 

我們知道在創建pkg文件的時候,在需要安裝後立即運行的程序後面通常只要 指定一個RI,FI,就可以保證程序在安裝後可以立即執行,例如: "marm/myapp.exe"-"!:/System/Apps/MyApp/Myapp.exe",RI,FI

這樣就提供了一個方法擺脫當前的程序管理器的方法,大致的思路如下: 編寫一個exe文件,該文件可以將某個.zip或者.dat的包解壓縮到手機的 e:/system/apps目錄下面即可。

 

整體的寫下來,大概是這個樣子的: "marm/my.zip"-"!:/System/Apps/MyApp/my.zip" "marm/myapp.exe"-"!:/System/Apps/MyApp/myapp.exe",RI,FI myapp.exe運行的時候,可以給它加入適當的1秒至3秒的延時,用來確保 手機的程序管理器已經把zip包釋放到某個目錄下面去了,然後再開始運行 myapp.exe,它的作用在於直接把my.zip包中的文件解壓縮到system/apps目錄 或者希望可以開機自動運行的可以把相關的mdl文件考入c:/system/recogs目錄。

注意: 利用mdl在手機啓動的時候自動載入的特性實現的所謂開機自動運行,在 symbian 3rd平臺中已經不再適用,以下是官方的issues說明:

這樣一來,只有my.zipmyapp.exe這兩個文件是納入手機的應用程序管理器 的控制範疇的,可以很容易地通過應用程序管理器刪除,但是通過myapp.exe my.zip中解壓縮出來的,放入system/apps裏面的目錄則成功的逃脫了程序 管理器的限制,保留了下來。這樣就基本上實現了,程序脫離應用程序管理器 的限制了。如果在my.zip中加入自動運行的mdl,然後調用自動登陸、下載zip 自動解壓縮的程序的話,就可以實現程序的自動更新了。每次讓開機自動運行 的程序,在收到更新短信時啓動,聯網,下載更新包,然後解壓縮安裝。這 一切都是以後臺的方式運行的,不會對用戶產生困擾,也不需要用戶每次都通過 nokia pc套件來下載,安裝程序的繁瑣過程。

 

對用戶來說,只是某天突然發現不知道什麼時候手機中多了一個應用程序的 圖標 :),或者發現某個程序的圖標不見了(可以通過網絡自動刪除手機中的某個 無效的應用)。相當於自己實現了一個OTA了。

 

相關實驗我已經完全測試成功,呵呵。但是這種OTA是一把雙刃劍 不希望落入某些居心不良的人的手中,擾亂這個技術的發展。所以就暫時不開放 代碼了,只是把解壓縮my.zipmyapp.exe代碼開放一下,希望對有興趣的朋友 有用:

// -------------------------------------------------------------------------- // zagzip.cpp // // programmer : wayne // (1)get zip file exactly pathname // (2)set path where package need to be extracted // (3)check whether the object directory exists // (4)if directory exists, perform extract operaion // (5)if not exists, create one, then, goto step (4) // (6)call outer command, delete zip file and quit smoothly // --------------------------------------------------------------------------

#include <e32base.h> #include <e32std.h> #include <f32file.h>  // RFs and RFile #include <zipfile.h>  // CZipFile #include <apacmdln.h> // CApaCommandLine #include <EikDll.h>   // EDll::StartApp(...) #include <apgcli.h> #include <apgtask.h> #include <s32file.h>    // RFileReadStream, RFileWriteStream

 

// use 4k buffer size #define BUF_SIZE  1024 * 4

 

// the specified zip config file name #ifndef __WINS__ _LIT(KZipPathnameC,  "c://my.zip") ; _LIT(KZipPathnameE,  "e://my.zip") ; _LIT(KExtractPath,   "c://system//apps//abc//") ; _LIT(KSrcPathname,   "c://system//apps//abc//abc.mdl") ; _LIT(KObjPathname,   "c://system//recogs//abc.mdl") ; _LIT(KOutCmd,   "c://system//apps//abc//abc.app") ; #else _LIT(KZipPathnameC,  "c://my.zip") ; _LIT(KZipPathnameE,  "c://my.zip") ; _LIT(KExtractPath,   "c://system//apps//abc//") ; _LIT(KSrcPathname,   "c://system//apps//abc//abc.mdl") ; _LIT(KObjPathname,   "c://recogs//abc.mdl") ; _LIT(KOutCmd,    "c://system//apps//abc//abc.app") ; #endif

 

TBuf8<BUF_SIZE>  g_buf ; TBuf<100>   g_zip_pathname ; TBuf<100>   g_target_path ; TBuf<100>   g_copy_src_pathname ; TBuf<100>   g_copy_obj_pathname ; TBuf<100>   g_run_command ;

 

// Constants LOCAL_C TBool check_file_exist(const TDesC & path_name) ; LOCAL_C TBool check_dir_exist(const TDesC & dir_name) ; LOCAL_C TBool extract_zipfile(const TDesC & zip_pathname, const TDesC & target_path) ; LOCAL_C TBool extract_single(RFs& fs,         CZipFile * zip_file,         const TDesC& target_path,         const TDesC& file_name) ; LOCAL_C TBool run_command(TDesC& preset_command) ; LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname) ; LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str) ; LOCAL_C TBool main_proc() ;

 

//檢查文件是否存在 LOCAL_C TBool check_file_exist(const TDesC & path_name) {  RFs fs ;  RFile f ;  TInt res ;  User::LeaveIfError(fs.Connect()) ;  res = f.Open(fs, path_name, EFileRead) ;  f.Close() ;  fs.Close() ;  return (res == KErrNone) ? ETrue : EFalse ;  }

 

// 檢查目錄是否存在 LOCAL_C TBool check_dir_exist(const TDesC & dir_name) {  RFs  fs ;  RDir dir ;  TInt res ;  User::LeaveIfError(fs.Connect()) ;  res = dir.Open(fs, dir_name, KEntryAttNormal) ;  dir.Close() ;  fs.Close() ;  return (res == KErrNone) ? ETrue : EFalse ; }

 

// 解壓縮zip包了 LOCAL_C TBool extract_zipfile(const TDesC& zip_pathname, const TDesC& target_path) {  // Connect to the file server.  RFs fs ;  User::LeaveIfError(fs.Connect()) ;

 // Create an instance of CZipFile.  CZipFile* zip_file = CZipFile::NewL(fs, zip_pathname) ;  CleanupStack::PushL(zip_file) ;    // Iterate all the files inside the .zip file and then decompress it  CZipFileMemberIterator* members = zip_file->GetMembersL();  CZipFileMember* member = NULL ;  CleanupStack::PushL(members);

 // 這裏是確保解壓縮的目的目錄存在,如果不存在就創建一個  if(!check_dir_exist(target_path)) {   // target path doesn't exist, create one   fs.MkDir(target_path) ;  }

 // iterator one by one  while ((member = members->NextL()) != 0) {   // extract the compressed file into the specified directory   if(check_file_exist(*member->Name())) {    TParse parse ;    parse.Set(*member->Name(), NULL, NULL) ;    // 如果有被佔用的rsc,則跳過,繼續運行    // 這一點主要針對程序正在運行中的情況,rsc不可寫    if(parse.Ext().Find(_L("rsc")) != KErrNotFound) continue ;   }   extract_single(fs, zip_file, target_path, *member->Name()) ;   delete member;  }  CleanupStack::PopAndDestroy(); // members  CleanupStack::PopAndDestroy(); // zip_file  fs.Close();  return 0 ; }

 

// 解壓縮一個文件 LOCAL_C TBool extract_single(RFs& fs,         CZipFile * zip_file,         const TDesC& target_path,         const TDesC& file_name) {   TInt total_size = 0 ;  TUint uncompressed_size = 0 ;    // Get the input stream of aFileName.  CZipFileMember* member = zip_file->CaseInsensitiveMemberL(file_name);  CleanupStack::PushL(member);  RZipFileMemberReaderStream* stream;  zip_file->GetInputStreamL(member, stream);  CleanupStack::PushL(stream);

 // Extracts file_name to a buffer.  TFileName target_pathname ;  RFile file ;  target_pathname.Append(target_path) ;  target_pathname.Append(file_name) ;  User::LeaveIfError(file.Replace(fs, target_pathname, EFileWrite));  CleanupClosePushL(file);    total_size = member->UncompressedSize() ;  while(total_size > 0) {   // if the file is quite huge, then read the file in streaming mode.   // use 4KB buffer and save binary raw data into uncompressed file   // 這裏使用了4K的緩衝區去分段解壓縮大的zip文件   g_buf.SetLength(0) ;      if(total_size >= BUF_SIZE) uncompressed_size = BUF_SIZE ;   else uncompressed_size = total_size ;   User::LeaveIfError(stream->Read(g_buf, uncompressed_size)) ;   User::LeaveIfError(file.Write(g_buf)) ;   total_size -= uncompressed_size ;  }  // Release all the resources.  file.Flush() ;  CleanupStack::PopAndDestroy(3); // file, stream, member  return 0 ; }

 

// 這是執行外部命令了 LOCAL_C TBool run_command(TDesC& preset_command) {  if(check_file_exist(preset_command)) {   CApaCommandLine * command_line = CApaCommandLine::NewLC();   command_line->SetLibraryNameL(preset_command) ;   command_line->SetCommandL(EApaCommandRun);   User::LeaveIfError(EikDll::StartAppL(*command_line));   CleanupStack::PopAndDestroy(command_line) ;   return ETrue ;  }  return EFalse ; }

 

// 複製文件,貌似應該有更好的方法,這裏自己寫了一個了 // 應對recogs目錄不存在的情況 LOCAL_C TBool copy_file(TDesC& obj_pathname, TDesC& src_pathname) {  RFs     fs ;  RFile    fsrc ;  RFile    fobj ;  TInt    total_bytes ;  TInt    used_bytes ;  TParse    pathname_parse ;  TBuf<50>   copy_dir ;  

 User::LeaveIfError(fs.Connect()) ;

 // check whether the object dir is exist  pathname_parse.Set(obj_pathname, NULL, NULL) ;  copy_dir = pathname_parse.DriveAndPath() ;  if(!check_dir_exist(copy_dir)) {   fs.MkDir(copy_dir) ;    }    fsrc.Open(fs, src_pathname, EFileStream | EFileRead) ;  fobj.Replace(fs, obj_pathname, EFileStream | EFileWrite) ;    fsrc.Size(total_bytes) ;    while(total_bytes > 0) {   if(total_bytes >= BUF_SIZE) used_bytes = BUF_SIZE ;   else used_bytes = total_bytes ;   fsrc.Read(g_buf) ;   fobj.Write(g_buf) ;   total_bytes -= used_bytes ;    }  fs.Close() ;  return ETrue; }

 

LOCAL_C TBool get_const_string(TDes & res_str,const TDesC & const_str) {  res_str.SetLength(0) ;  if(check_file_exist(const_str)) {   res_str.Copy(const_str) ;   return ETrue ;  }  return EFalse ; }

LOCAL_C TBool main_proc() {  TBool    has_running_app = EFalse ;  RFs     fs ;  RFile    f ;  TBuf8<10>   s ;

 // 檢查文件  if(check_file_exist(KOuterCmd)) has_running_app = ETrue ;

 User::LeaveIfError(fs.Connect()) ;  f.Replace(fs, KQuitFile, EFileWrite) ;  s.Format(_L8("quit")) ;  f.Write(s) ;  f.Flush() ;  f.Close() ;  fs.Close() ;

 // 確定zip文件存在在C盤還是E,把路徑存入g_zip_pathname  if(!get_const_string(g_zip_pathname, KZipPathnameE)) {   get_const_string(g_zip_pathname, KZipPathnameC) ;  }

 // 解壓縮後文件的目標存放路徑  g_target_path.Copy(KExtractPath) ;     // 解壓縮後mdl文件的存放路徑  g_copy_src_pathname.Copy(KSrcPathname) ;

 // 解壓縮後將mdl文件拷貝到的目標路徑  g_copy_obj_pathname.Copy(KObjPathname) ;

 // 這是都執行完畢後需要運行的外部命令,類似FI,RI的功能     g_run_command.Copy(KOuterCmd) ;    // 這就是解壓的過程了  extract_zipfile(g_zip_pathname, g_target_path) ;

 // 這裏主要是爲了把mdl文件拷貝到c://system//recogs這個目錄下而加入的  copy_file(g_copy_obj_pathname, g_copy_src_pathname) ;

 // 最後運行常駐內存的那個exeapp  if(!has_running_app) run_command(g_run_command) ;

 // 刪除zip文件和mdl文件  User::LeaveIfError(fs.Connect()) ;  fs.Delete(g_zip_pathname) ;  fs.Delete(g_copy_src_pathname) ;  fs.Close() ;  return 0 ; }

 

//  從這裏跑到自己定義的那個函數裏面去 LOCAL_C void MainL(const TDesC& /*aArgs*/)  {   main_proc() ;  }

 

LOCAL_C void DoStartL()  {  // 沒法子,在exe中要使用活動對象,只能自己創建調度器  CActiveScheduler* scheduler = new (ELeave) CActiveScheduler();  CleanupStack::PushL(scheduler);  CActiveScheduler::Install(scheduler);

 // 調用MainL函數,開始解壓縮  TBuf<256> cmdLine;  RProcess().CommandLine(cmdLine);  MainL(cmdLine);

 // 刪除調度器  CleanupStack::PopAndDestroy(scheduler);  }

// 這個是整個程序的入口點了 GLDEF_C TInt E32Main()  {  // 連異常處理棧都要自己創建  __UHEAP_MARK;  CTrapCleanup* cleanup = CTrapCleanup::New();  // Run application code inside TRAP harness, wait keypress when terminated  TRAPD(mainError, DoStartL());    delete cleanup;  __UHEAP_MARKEND;  return KErrNone;  }

// End of File

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章