Chuyển trạng thái trong cập nhật phần mềm động sử dụng phương pháp cập nhật tại chỗ

Chúng ta đều biết các phần mềm đều có các thay đổi trong suốt vòng đời hoạt động của mình.

Những thay đổi đó có thể do phát hiện lỗi trong quá trình vận hành; có thể do thêm hoặc bớt một số

chức năng để phù hợp với nhu cầu thực tế hiện tại, Vì vậy cập nhật phần mềm là hoạt động thường

xuyên diễn ra.

Theo cách truyền thống, việc cập nhật thường yêu cầu dừng và khởi động lại ứng dụng. Với cách này,

tương tác của người dùng với ứng dụng sẽ bị gián đoạn. Nhiều ứng dụng không thể tạm dừng hoặc

không muốn tạm dừng. Ví dụ với các hệ thống quan trọng (hệ thống ngân hàng, bệnh viện, ), việc

gián đoạn này là không chấp nhận được. Với các hệ thống này người ta thực hiện cập nhật phần mềm

động (dynamic software update) - cho phép các hệ thống đang chạy được cập nhật nhanh chóng mà

không bị gián đoạn dịch vụ, việc này làm cho sự tương tác của người dùng với ứng dụng không bị gián

đoạn khi thực hiện cập nhật ứng dụng lên phiên bản mới.

Bài viết này cung cấp một số phương pháp đã được sử dụng trong cập nhật phần mềm động cùng ưu,

nhược điểm của từng phương pháp.

pdf6 trang | Chia sẻ: Thục Anh | Ngày: 11/05/2022 | Lượt xem: 469 | Lượt tải: 0download
Nội dung tài liệu Chuyển trạng thái trong cập nhật phần mềm động sử dụng phương pháp cập nhật tại chỗ, để tải tài liệu về máy bạn click vào nút DOWNLOAD ở trên
Dương Thị Mai Nga, Huỳnh Ngọc Thọ Chuyển Trạng Thái Trong Cập Nhật Phần Mềm Động Sử Dụng Phương Pháp Cập Nhật Tại Chỗ Dương Thị Mai Nga1 và Huỳnh Ngọc Thọ 2 1,2 Đại học Công nghệ Thông tin và Truyền thông Việt Hàn – Đại học Đà Nẵng {dtmnga, hntho}@vku.udn.vn Tóm tắt. Chúng ta đều biết các phần mềm đều có các thay đổi trong suốt vòng đời hoạt động của mình. Những thay đổi đó có thể do phát hiện lỗi trong quá trình vận hành; có thể do thêm hoặc bớt một số chức năng để phù hợp với nhu cầu thực tế hiện tại, Vì vậy cập nhật phần mềm là hoạt động thường xuyên diễn ra. Theo cách truyền thống, việc cập nhật thường yêu cầu dừng và khởi động lại ứng dụng. Với cách này, tương tác của người dùng với ứng dụng sẽ bị gián đoạn. Nhiều ứng dụng không thể tạm dừng hoặc không muốn tạm dừng. Ví dụ với các hệ thống quan trọng (hệ thống ngân hàng, bệnh viện, ), việc gián đoạn này là không chấp nhận được. Với các hệ thống này người ta thực hiện cập nhật phần mềm động (dynamic software update) - cho phép các hệ thống đang chạy được cập nhật nhanh chóng mà không bị gián đoạn dịch vụ, việc này làm cho sự tương tác của người dùng với ứng dụng không bị gián đoạn khi thực hiện cập nhật ứng dụng lên phiên bản mới. Bài viết này cung cấp một số phương pháp đã được sử dụng trong cập nhật phần mềm động cùng ưu, nhược điểm của từng phương pháp. Từ khóa: cập nhật động, chuyển trạng thái, cập nhật phần mềm động. Abstract. Softwares always change throughout their life cycle. Such changes may be caused by error detection during operation; may be due to adding or removing some features to suit the current require- ments, So software update is a regular activity. Traditionally, updating often requires stopping and restarting the application. In this way, the user's interaction with the application will be interrupted. Many applications can't pause or don't want to pause. For example with critical sytems (banking systems, hospitals, etc.), this interruption is unac- ceptable. The dynamic software update is performed with these systems - allowing running systems to be updated quickly without service interruption. This article provides some methods that have been used in dynamic software updates and the ad- vantages and defects of each method. Keywords: live update, state transfer, dynamic software update. 1 Đặt vấn đề Việc nâng cấp bằng cách dừng/ khởi động lại ứng dụng vẫn đang là phương pháp cập nhật của đại đa số ứng dụng hiện nay. Nhiều hệ thống yêu cầu phải hoạt động liên tục nhưng dù sao cũng phải được cập nhật để sửa lỗi và thêm các tính năng mới. Các nhà cung cấp dịch vụ internet, nhà cung cấp thẻ tín dụng, cửa hàng trực tuyến, luôn phải duy trì hoạt động 24/7, một giờ ngừng hoạt động có thể tiêu tốn hàng trăm nghìn, thậm chí hàng triệu đô la [1], [2]. Ngày nay, nhiều hệ thống muốn nâng cấp trực tuyến thay vì phải dừng và khởi động lại mỗi khi nó được điều chỉnh, một ví dụ dễ nhận thấy là các hệ điều hành. Ngay cả các ứng dụng iPhone và Android cũng hỗ trợ cập nhật động: khi người dùng thoát khỏi ứng dụng đang chạy, trạng thái của nó có thể được lưu lại để kiểm soát; nếu người dùng quay trở lại ứng dụng sau khi nâng cấp nó, phiên bản mới có thể khôi phục các trạng thái đã được lưu lại trước đó. Trong quá trình cập nhật, một vấn đề được quan tâm là việc chuyển các trạng thái từ phiên bản cũ sang phiên bản mới. Việc chuyển trạng thái thực hiện chuyển nội dung các biến ở phiên bản cũ sang các biến ở phiên bản mới. 241 KỶ YẾU HỘI THẢO KHOA HỌC QUỐC GIA CITA 2020 “CNTT VÀ ỨNG DỤNG TRONG CÁC LĨNH VỰC” Bài viết giới thiệu một số phương pháp đã được sử dụng rộng rãi trong cập nhật phần mềm động là phương pháp dựa trên điểm cập nhật và phương pháp cập nhật mọi lúc (bao gồm POLUS và Ginseng). Đồng thời bài viết cũng phân tích ưu điểm, hạn chế của từng phương pháp và đề xuất hướng giải quyết. 2 Phương pháp dựa trên điểm cập nhật (update-point based approach) [3] giới thiệu phương pháp cơ bản cho việc cập nhật phần mềm động và đã được triển khai trên máy trạm Sun 3/60 chạy SunOS, áp dụng chuyển đổi cho các ứng dụng viết bằng ngôn ngữ C, tuy nhiên có thể mở rộng cho các ngôn ngữ hướng thủ tục khác. Ở đây việc phát triển phiên bản mới của ứng dụng được thực hiện và kiểm định riêng, hệ thống chỉ đảm bảo các thay đổi được cài đặt vào đúng thời điểm sao cho việc chuyển đổi xảy ra đúng đắn. Khi một phiên bản mới của phần mềm được cài đặt, một tiến trình mới (new process) được tạo ra ứng với phiên bản mới. Nếu không còn hàm nào thay đổi giữa các phiên bản thì các trạng thái của phiên bản cũ sẽ được chuyển sang phiên bản mới, sau đó tiến trình cũ sẽ được loại bỏ. Cụ thể, các trạng thái sẽ được chuyển vào một thời điểm thích hợp trong quá trình chuyển từ phiên bản cũ sang phiên bản mới. Người dùng hầu như sẽ không thấy sự gián đoạn trong hoạt động của ứng dụng. Các mô đun chính của hệ thống đươc trình bày ở Hình 1. Tất cả các lệnh liên quan đến việc cập nhật động được thực hiện ở Modification Shell. Hình. 1. Các mô đun chính của hệ thống Danh sách các lệnh cùng với bản tóm tắt chức năng của chúng được liệt kê ở Bảng 1. Bảng 1. Các câu lệnh của Modification Shell Câu lệnh Chức năng cd dir Chuyển thư mục làm việc tới dir help Hiển thị thông báo kill Xóa bỏ tiến trình đang hoạt động quit Đóng Modification Shell re new-prog routines [init] Thay thế chương trình đang chạy bằng new-prog, các hàm thay đổi được chỉ ra trong file routines và init là routine khởi tạo ban đầu. run prog [arg1, ] Chạy chương trình prog tty [tty-name] Thiết lập thiết bị đầu cuối ở tty-name Để chuyển trạng thái, tiến trình của phiên bản cũ được thực thi để gọi thư viện nơi lưu trữ các thông tin về dữ liệu và địa chỉ ngăn xếp. Những thông tin này được lưu trữ trong các biến và hệ thống thay thế biết rõ các biến này. Hệ thống sẽ đọc những thông tin này và viết chúng vào các biến tương ứng trong tiến trình Run Modification Shell Symbol Table Replace Process Handling Run-time Library 242 Dương Thị Mai Nga, Huỳnh Ngọc Thọ của phiên bản mới. Tiến trình mới sau đó được thực thi để gọi thư viện nơi điều chỉnh dữ liệu và không gian ngăn xếp tương ứng với những thông tin trên. Sau đó các thanh ghi máy (machine registers) được sao chép. Với bộ đếm chương trình (program counter), giá trị mới của nó được xác định bằng cách tìm địa chỉ mới của chương trình trong Symbol Table cho phiên bản mới và điều chỉnh. Sau khi việc chuyển trạng thái kết thúc, tiến trình cũ sẽ được loại bỏ và tiến trình mới tiếp tục hoạt động. Tuy nhiên vẫn còn một số vấn đề trong chuyển đổi trạng thái mà [3] chưa giải quyết được: · Duy trì tính nhất quán của các con trỏ khi thực hiện sao chép dữ liệu từ phiên bản cũ sang phiên bản mới; · Quyết định thời điểm thực hiện chuyển trạng thái để đảm bảo việc chuyển đổi qua phiên bản mới được thực hiện đúng đắn; · Đảm bảo sự đúng đắng của các tập tin I/O sau thay đổi; · Xử lý sự thay đổi ở giá trị trả về và định dạng tham số của hàm; · Xử lý việc thêm, xóa dữ liệu toàn cục; Ngoài ra phương pháp dựa trên điểm cập nhật này còn có một số nhược điểm cơ bản: Thứ nhất là khả năng tìm thấy điểm cập nhật hợp lí phụ thuộc nhiều vào khả năng phân tích của trình biên dịch hoặc lập trình viên. Với các ngôn ngữ lập trình linh hoạt như C, trình biên dịch thường gặp nhiều khó khăn trong việc phân tích con trỏ và phân tích bí danh. Mặc dù đã có đề xuất nhằm hỗ trợ trình biên dịch [4] tuy nhiên đề xuất này chỉ dành cho các ứng dụng đơn luồng và nó không duy trì khả năng tương thích nhị phân. Do đó, nó không áp dụng được cho các tập tin nhị phân đã được biên dịch và phần mềm hiện đang chạy. Thứ hai, rất khó tìm điểm cập nhật cho phần mềm đa luồng, nếu một điểm cập nhật không thể phát hiện kịp thời, một vài cập nhật liên quan tới bảo mật sẽ bị trì hoãn khiến hệ thống dễ bị tấn công. Thứ ba, người vận hành có thể không kiểm soát được quá trình cập nhật động do không biết được thời điểm thực hiện cập nhật. Do đó có thể dẫn đến vấn đề một bản cập nhật mới vô tình được áp dụng khi bản cập nhật hiện tại đang được tiến hành. Hơn nữa trong nghiên cứu của mình, Gupta [5] đã sử dụng các phương pháp hình thức để hiểu rõ hơn về tính hợp lệ của việc cập nhật động và đã chứng minh rằng việc tìm kiếm các điểm cập nhật an toàn thể thực thi việc cập nhật nói chung là không thể giải quyết được. 3 Cập nhật bất kì lúc nào 3.1 POLUS (POwerful Live Updating System) Nhận thức được những khó khăn trong cách tiếp cận dựa trên điểm cập nhật, [6] trình bày phương pháp cho phép thực hiện bản cập nhật bất kì lúc nào. [6] giới thiệu POLUS, một công cụ hỗ trợ việc bảo trì phần mềm, trong đó có việc cập nhật lên phiên bản mới. Với POLUS, cả mã nguồn và dữ liệu của phiên bản cũ và phiên bản mới đều được phép cùng tồn tại. [6] đã ứng dụng POLUS để thực hiện cập nhật ba ứng dụng máy chủ phổ biến: vsftpd (a commonly used FTP daemon), sshd (secure shell daemon) in OpenSSH suite và apache HTTP server. POLUS được thiết kế để hỗ trợ các cập nhật phần mềm liên quan tới mã nguồn, dữ liệu và thỏa mãn các tiêu chí sau: · Khả năng tương thích nhị phân (Binary Compatibility) · Hỗ trợ đa luồng (Multithreading Support) · Khôi phục các trạng thái bị hỏng (Recovery of Tainted State) do các lỗi bên trong phần mềm hoặc do các cuộc tấn công từ bên ngoài. · Tính khả dụng và khả năng quản lý (Usability and Manageability) · Chi phí thấp (Low Overhead) POLUS gồm ba thành phần: · Patch constructor: có dạng như một trình biên dịch, nơi phát hiện sự khác biệt về ngữ nghĩa giữa hai phiên bản phần mềm kế tiếp. 243 KỶ YẾU HỘI THẢO KHOA HỌC QUỐC GIA CITA 2020 “CNTT VÀ ỨNG DỤNG TRONG CÁC LĨNH VỰC” · Patch injector: nơi thực hiện tiến trình để áp dụng các bản cập nhật · Runtime library: cung cấp một số hàm tiện ích để quản lý các bản vá POLUS cho Patch injector. Về chuyển đổi trang thái, ý tưởng chính của [6] là cho phép cùng tồn tại cả dữ liệu phiên bản cũ và phiên bản mới và duy trì sự kết hợp bằng cách gọi một số hàm đồng bộ trạng thái bất cứ khi nào có yêu cầu truy cập để ghi vào một trong hai phiên bản. Khi không có hàm nào thao tác với dữ liệu phiên bản cũ, quá trình cập nhật được kết thúc một cách an toàn. POLUS chỉ quan tâm tới các trạng thái toàn cục (như các biến toàn cục) mà không quan tâm tới các trạng thái cục bộ (ví dụ như ngăn xếp cục bộ, biến cục bộ) và xem các hàm thao tác với trạng thái như các hộp đen. POLUS được thiết kết để hỗ trợ cả ứng dụng đơn luồng và đa luồng. Việc cho phép cả dữ liệu cũ và dữ liệu mới đều được phép cùng tồn tại là vì các hàm thao tác với dữ liệu cũ vẫn còn hoạt động nên có thể có các truy cập đồng thời vào thể hiện cũ và thể hiện mới của biến. POLUS đảm bảo sự gắn kết giữa chúng bằng cách sử dụng các hàm đồng bộ hóa trạng thái được cung cấp bởi Patch constructor. Khi một bản cập nhật động được thực thi, Patch injector sẽ bảo vệ cả thể hiện cũ và mới của hai phiên bản và liên kết với trình xử lý tín hiệu để bắt các lần ghi vào từng thể hiện của từng phiên bản. Trình xử lý tín hiệu sẽ gọi các hàm đồng bộ hóa trạng thái tương ứng để chuyển các trạng thái đã sửa đổi từ phiên bản này sang phiên bản khác. [6] đã chứng minh rằng POLUS có thể thực hiện việc cập nhật cho các phần mềm máy chủ thực, lớn và phức tạp mà không làm gián đoạn dịch vụ của chúng. Tuy nhiên POLUS cũng còn một số hạn chế khi sử dụng. Thứ nhất, không phải hệ thống nào cũng đủ không gian nhớ cho phép lưu trữ cùng lúc trạng thái của phiên bản cũ và phiên bản mới nên không áp dụng được với tất cả các trường hợp. Thứ hai, do việc vẫn duy trì khả năng tương thích nhị phân để hỗ trợ các hệ thống cũ hoặc các hệ thống đã hoạt động, điều này khiến việc triển khai POLUS thêm phần phức tạp và có thể gây khó khăn cho việc xử lý một số vòng lặp vô hạn trong quá trình cập nhật (mặc dù việc cập nhật các hàm có lời gọi các vòng lặp như vậy là khá hiếm trong thực tế). 3.2 Ginseng Ginseng[4] thực hiện cập nhật phần mềm động cho các ứng dụng viết bằng ngôn ngữ C. Phần mềm được biên dịch một cách đặc biệt để chúng có thể chủ động tạo ra các bản vá và thực hiện cập nhật một cách tự động. Ginseng đảm bảo dữ liệu luôn được cập nhật đầy đủ và đúng đắn. [4] đã sử dụng Ginseng để xây dựng và tự động áp dụng các bản vá cho ba chương trình máy chủ nguồn mở: Very Secure FTP daemon, OpenSSH sshd daemon, và GNU Zebra. Ginseng đã phát triển một vài kỹ thuật mới bao gồm các cách mới để xử lý việc chuyển đổi dữ liệu của các biến có sự thay đổi kiểu dữ liệu, cho phép cập nhật động các vòng lặp vô hạn (công việc vẫn còn khó khăn khi sử dụng POLUS[6]) và cho phép cập nhật một cách có hiệu quả các chương trình với việc sử dụng con trỏ hàm. [4] cũng đã phát triển các công cụ để tự động tạo ra bản vá động bằng cách so sánh hai phiên bản chương trình nhằm giảm công việc của lập trình viên. Quan trọng hơn, Ginseng thực hiện hai phân tích để xác định thời điểm thực hiện việc cập nhật được an toàn trong khi ứng dụng vẫn đang hoạt động. Cơ sở lý thuyết cho việc phân tích này đã được trình bày ở [7]. Ginseng bao gồm ba thành phần: · Compiler: tạo ra tập tin thực thi có thể cập nhật (v1) và một số thông tin phân tích, thông tin nguyên mẫu từ phiên bản ban đầu (v1.c); sau đó tạo ra bản vá động từ tập tin lưu trữ sự khác biệt (p2.c) và thông tin phiên bản hiện tại. · Patch generator: tạo ra tập tin p2.c thể hiện sự khác biệt giữa hai phiên bản chương trình (v1.c và v2.c) · Runtime system: liên kết các bản vá động vào chương trình đang chạy, hoàn thành cập nhật trực tuyến. Để thực hiện chuyển trạng thái, đầu tiên Patch generator xác định các thông tin thay đổi giữa các phiên bản (như các biến toàn cục, các hàm hoặc kiểu dữ liệu). Sau đó, với từng thông tin thay đổi này, Patch generator tạo ra một hàm chuyển đổi thực hiện chuyển dữ liệu từ mô tả cũ sang mô tả mới. Compiler thực hiện chèn mã nguồn vào chương trình để chương trình thực hiện những hàm này sau một bản vá động. 244 Dương Thị Mai Nga, Huỳnh Ngọc Thọ Người dùng có thể tự tạo các hàm chuyển đổi trạng thái tùy chọn và được thực thi vào thời điểm cập nhật để chuyển đổi trạng thái toàn cục. Người dùng cũng có thể điều chỉnh hàm chuyển đổi kiểu dữ liệu. Ví dụ, nếu một kiểu cấu trúc muốn mở rộng thêm một trường, Patch generator sẽ tạo ra mã nguồn để sao chép các trường chung và thêm khởi tạo mặc định cho các trường mới được thêm vào. Cách tiếp cận này tạo ra bản vá một cách hiệu quả, tuy nhiên yêu cầu một vài điều chỉnh thủ công. Sau khi bản vá được tạo và trình chuyển đổi trạng thái/ kiểu dữ liệu đã được viết, chúng chuyển kết quả cho Ginseng, và kết quả cuối cùng được biên dịch sang thư viện dùng chung để có thể liên kết vào chương trình đang chạy. Có thể thấy Ginseng đã cải thiện đáng kể so với công việc trước đây của họ [8] - yêu cầu chỉ định khi nào cần cập nhật. Hơn nữa, Ginseng đã cho thấy tính thực tiễn của nó bằng cách áp dụng vào ba ứng dụng máy chủ lớn đã nêu ở trên. Tuy nhiên, việc sử dụng chuyển đổi trình biên dịch không đáp ứng yêu cầu về khả năng tương thích nhị phân và hạn chế với các ứng dụng đã biên dịch và hiện đang hoạt động. Hơn nữa, cho đến nay Ginseng và tiền thân của nó chỉ áp dụng cho phần mềm đơn luồng. 3.3 Bảng tổng hợp Từ những phân tích ở trên có thể tổng hợp lại các ưu, nhược điểm của từng phương pháp trong bảng sau: Bảng 2. Tổng hợp các phương pháp Phương pháp Tiêu chí POLUS Ginseng Phương pháp dựa trên điểm cập nhật Khả năng tương thích nhị phân Có Không Không Hỗ trợ các tập tin đã được biên dịch và hệ thống hiện đang hoạt động Có Không Không Hỗ trợ ứng dụng đơn luồng Có Có Có Hỗ trợ ứng dụng đa luồng Có Không Không Thời điểm tiến hành cập nhật Có thể cập nhật bất kỳ lúc nào Có thể cập nhật bất kỳ lúc nào Trình biên dịch hoặc lập trình viên xác định điểm cập nhật 4 Kết luận Với các phương pháp đã giới thiệu ở trên, để thực hiện cập nhật phần mềm động thì khi có bản phát hành mới chúng ta cần tạo ra bản vá động chứa các hàm mới, các biến toàn cục mới, mã chuyển đổi trạng thái trong đó điều chỉnh cả dữ liệu và trạng thái điều khiển. Bản vá này được tải vào chương trình đang chạy và việc thực thi mã cũ được chuyển hướng sang mã mới. Chuyển hướng như vậy được kích hoạt bằng cách biên dịch chương trình gốc một cách đặc biệt như trong Ginseng [4] hoặc ép buộc trên hệ thống đang hoạt động như ở POLUS[6]. Mặc dù phương pháp cập nhật tại chỗ và cập nhật mọi lúc được sử dụng phổ biến, tuy nhiên vẫn có một số nhược điểm sau: (1) các trình biên dịch được sử dụng để hỗ trợ cập nhật tại chỗ đôi khi sử dụng các phân tích tĩnh để đảm bảo tính toàn vẹn ngữ nghĩa khi thực hiện các phép biến đổi chương trình, điều này sẽ buộc một số chương trình phải thay đổi để được biên dịch chính xác; (2) suy đoán về hành vi của chương trình được cập nhật đặt thêm gánh nặng cho lập trình viên khi phải suy luận về chương trình, các điểm trong chương trình có thể xảy ra cập nhật, mã thay đổi trong bản vá và mã chuyển đổi trạng thái; (3) tất cả trạng thái của chương trình mới phải được khởi tạo một cách rõ ràng, thậm chí cả những trạng thái không có ở phiên bản cũ. Những hạn chế này có thể được giải quyết bằng cách thực hiện cập nhật dựa trên chuyển trạng thái (state transfer-based updating). 245 KỶ YẾU HỘI THẢO KHOA HỌC QUỐC GIA CITA 2020 “CNTT VÀ ỨNG DỤNG TRONG CÁC LĨNH VỰC” Tài liệu tham khảo 1. D. Oppenheimer, A. Brown, J. Beck, D. Hettena, J. Kuroda, N. Treuhaft, D. A. Patterson, and K. Yelick. Roc-1: Hardware support for recovery-oriented computing. IEEE Trans. Comput., 51(2):100–107, 2002 2. S. Parker. A simple equation: IT on = Business on. The IT Journal, Hewlett Packard, 2001. 3. Deepak Gupta, Pankaj Jalote: On-line Software Version Change UsingState Transfer Between Processes. SOFTWARE—PRACTICE AND EXPERIENCE, VOL. 23(9), 949–964 (SEPTEMBER 1993) 4. I. Neamtiu, M. Hicks, G. Stoyle, and M. Oriol. Practical dynamic software updating for c. In Proc. PLDI, pages 72– 83, June 2006. 5. D. Gupta, P. Jalote, and G. Barua. A formal framework for on-line software version change. IEEE Transaction on Software Engineering, 22(2):120–131, February 1996 6. Haibo Chen, Jie Yu, Rong Chen, Binyu Zang, and Pen-Chung Yew. Polus: A powerful live updating system. In ICSE, pages 271–281, 2007 7. G. Stoyle, M. Hicks, G. Bierman, P. Sewell, and I. Neamtiu. Mutatis Mutandis: Safe and predictable dynamic software updating. In Proc. POPL, 2005 8. M. W. Hicks, J. T. Moore, and S. Nettles. Dynamic software updating. In Proc. PLDI, pages 13–23, 2001. H. Chen, R. Chen, F. Zhang, B. Zang, and P.-C. Yew. Live updating operating systems using virtualization. In Proc. VEE, pages 35–44, Ottawa, Canada, June 2006 246

Các file đính kèm theo tài liệu này:

  • pdfchuyen_trang_thai_trong_cap_nhat_phan_mem_dong_su_dung_phuon.pdf