คำนำ
บทความนี้ส่วนใหญ่แนะนำความตั้งใจ Android และวิเคราะห์กระบวนการจับคู่แบบสอบถามเจตนาจากมุมมองของซอร์สโค้ด Android
บทนำ intten
ความตั้งใจของจีนหมายถึง "ความตั้งใจ" และความตั้งใจเป็นแนวคิดที่เป็นนามธรรมมาก ดังนั้นระบบ Android ระบุอย่างชัดเจนว่าความตั้งใจสามารถวัดได้สองด้าน
คุณลักษณะหลัก: รวมถึงการกระทำและข้อมูล ในหมู่พวกเขาการกระทำจะใช้เพื่อแสดงถึงความตั้งใจในการกระทำที่แสดงโดยเจตนาและข้อมูลจะใช้เพื่อแสดงข้อมูลที่ดำเนินการโดยการกระทำ
แอตทริบิวต์รอง: รวมถึงหมวดหมู่ประเภทส่วนประกอบและความพิเศษ หมวดหมู่แสดงหมวดหมู่ประเภทแสดงถึงประเภทข้อมูลของข้อมูลและส่วนประกอบสามารถใช้เพื่อระบุการตอบสนองของเจตนาเฉพาะ (ตัวอย่างเช่นการระบุความตั้งใจที่จะเป็นคลาสคลาสภายใต้แพ็คเกจ) และใช้งานพิเศษเพื่อดำเนินการอื่น ๆ ข้อมูล.
มีเจตนาหลักสองประเภทในระบบ Android ซึ่งแสดงเจตนา (เจตนาที่ชัดเจน) และความตั้งใจที่ซ่อนอยู่ (เจตนาโดยนัย)
ความตั้งใจที่ชัดเจน: ความตั้งใจประเภทนี้แสดงให้เห็นอย่างชัดเจนว่าองค์ประกอบใดที่จะค้นหา ในรหัสคุณสามารถล็อควัตถุเป้าหมายผ่าน setClassName หรือ setComponent
ความตั้งใจโดยนัย: ความตั้งใจประเภทนี้ไม่ได้ระบุว่าส่วนประกอบใดที่จะเริ่มต้น แต่ตั้งค่าการกระทำข้อมูลและหมวดหมู่เพื่อให้หน้าจอระบบเป็นองค์ประกอบที่เหมาะสม
ถัดไปเขียนตัวอย่างรหัสสองตัวอย่างเพื่อแนะนำความตั้งใจที่จะอธิบายและการบอกกล่าว อย่างแรกคือเจตนาที่ชัดเจน:
โมฆะส่วนตัว startExplicitIntEntEdComponent () {เจตนาเจตนา = ความตั้งใจใหม่ (); componentName component = new ComponentName ("com.example.photocrop", "com.ex" ample.photocrop.mainactivity "); เจตนา);} โมฆะส่วนตัว startexplentIntentWithClassName () {เจตนาเจตนา = ความตั้งใจใหม่ (); Intent.setClassName ("com.example.photocrop", "com.example.p hotocrop.mainactivity");อย่างไรก็ตามจากซอร์สโค้ดฉันพบว่า setClassName ยังใช้ componentName เพื่อให้บรรลุเจตนาอย่างชัดเจน ซอร์สโค้ดมีดังนี้:
ความตั้งใจสาธารณะ setClassName (packagename สตริง, classname สตริง) {mcomponent = new componentName (packagename, className);จากนั้นตัวอย่างโค้ดของเจตนาโดยนัย ที่นี่ฉันใช้กิจกรรมเพื่อทำเครื่องหมายตัวกรองเจตนาบางอย่างเป็นตัวอย่างจากนั้นเขียนเจตนาที่จะเริ่มต้น
<กิจกรรม Android: name = ". sendintentType"> <intent-filter> <การกระทำ Android: name = "JustTest"/> <หมวดหมู่ Android: name = "justCategory" </intent-f ilter> </กิจกรรม>
ใน AndroidManifest.xml ใช้ในปัจจุบันตัวกรองเจตนาจะถูกเพิ่มเข้าไปในคลาส SendIntentType รหัสที่เริ่มกิจกรรมมีดังนี้:
โมฆะส่วนตัว startImpllictintent () {เจตนาเจตนา = ความตั้งใจใหม่ ();ในกระบวนการจับคู่กระบวนการโดยเจตนาสามรายการที่ระบุโดยตัวกรองเจตนาจะถูกใช้เป็นมาตรฐานอ้างอิง
การจัดการข้อมูลกิจกรรม
จากการวิเคราะห์ข้างต้นจะเห็นได้ว่าในกระบวนการของความตั้งใจในการจับคู่ระบบคุณต้องจัดการข้อมูลกิจกรรมทั้งหมดในระบบปัจจุบันก่อน ข้อมูลของกิจกรรมถูกรวบรวมและจัดการโดย PackageNagerservice เมื่อสแกน APK ซอร์สโค้ดที่เกี่ยวข้องมีดังนี้:
// ประมวลผลข้อมูล attural ที่แนบมา n = pkg.activities.size (); a .info.processName = fixprocessName (pkg.applicationinfo.processname, a.info.processname, pkg.applicationinfo.uid);
ในรหัสข้างต้นมีโครงสร้างข้อมูลที่สำคัญสองประการดังแสดงในรูปด้านล่าง
เมื่อรวมกับโครงสร้างข้อมูลของรหัสและรูปด้านบนสามารถเห็นได้:
MacItivitys เป็นประเภทกิจกรรมที่มีการรวมตัวกัน นอกจากนี้ยังมีตัวแปร mactivies ภายในโครงสร้างข้อมูลนี้
ข้อมูลที่เกี่ยวข้องกับข้อมูลทั้งหมดที่ได้รับจาก APK (รวมถึงฉลาก IntentFilter ที่ประกาศใน XML) จะถูกบันทึกโดย PackageParser.Activity
รหัสก่อนหน้านี้เรียกฟังก์ชัน addactivity เพื่อให้ข้อมูลส่วนตัวเสร็จสมบูรณ์ รหัสของฟังก์ชัน addactivity มีดังนี้:
public void addactivity (packageparser.Activity A, ประเภทสตริง) {Boolean SystemApp = ISSYSTEMAPP (A.Info.ApplicationInfo); int j = 0; / ลำดับความสำคัญของ APK ที่ไม่ใช่ระบบไม่ต้องเป็น 0 intent.setPriority (0);} addFilter (เจตนา);}}มาดูฟังก์ชั่น addfilter กันเถอะ ซอร์สโค้ดฟังก์ชั่นมีดังนี้:
โมฆะสาธารณะ addfilter (f f) {// mfilters เพื่อบันทึกข้อมูล intentfilter ทั้งหมด mfilters.add (f); ประเภท: "); ถ้า (nums == 0 && numt == 0) {register_intent_filter (f.actionsitertor (), mactintofilter," การกระทำ: ");} ถ้า (numt! = 0) {ตัวกรอง (), mtypedactintofilter, "typedaction:");}}}}มีโครงสร้างข้อมูลอีกหลายอย่างที่นี่
หลังจากทำความเข้าใจโครงสร้างข้อมูลโดยประมาณแล้วลองดูที่การใช้งานฟังก์ชั่นของ register_intent_filter:
ส่วนตัวสุดท้าย int register_intent_filter (ตัวกรอง, iterator <string> i, arraymap <string, f [] dest, string, string, if (i == null) {return 0;} int num = 0; ในขณะที่ (i.hasnext () ) {string name = ipxt ();จากนั้นก็เป็นฟังก์ชั่น AddFilter อีกอย่างหนึ่งซึ่งเป็นฟังก์ชั่นที่หนักหน่วง
โมฆะสุดท้ายเป็นโมฆะ addFilter (arraymap <string, f [] แผนที่, ชื่อสตริง, ตัวกรอง) {f [] array = map.get (ชื่อ); (ชื่ออาร์เรย์); if (i <n) {array [i] = filter;} else {f [] newa = newsray ((n*3)/2); n] = ตัวกรอง;ในความเป็นจริงรหัสยังคงง่ายมาก หากไม่มีอาร์เรย์ F ให้สร้างอาร์เรย์ที่มีความจุ 2 และกำหนดองค์ประกอบหมายเลข 0 ให้กับตัวกรอง
การวิเคราะห์แบบสอบถามการจับคู่ความตั้งใจ
ลูกค้าผ่านฟังก์ชั่น queryIntentActivities เอาต์พุตโดย ApplicationPackAgemanager เพื่อเริ่มต้นการร้องขอการสืบค้นไปยัง PackagEnageERService
@Override รายการสาธารณะ <RonesVeInfo> queryIntentActivities (เจตนาเจตนา, ค่าสถานะ int) {return QuryIntititiesAser (เจตนา, ธง, mcontext.get userid ());} / ** @hide เหมือนกับข้างบน แต่สำหรับผู้ใช้เฉพาะ* / @Override สาธารณะสาธารณะ รายการ <ResolveInfo> queryIntentActivitiesAsuser (เจตนาเจตนา, ค่าสถานะ int, intimeId) ifneeded (mcontext.getContentResolver ()), ธง, userId);} catch (RemoteException e) }จะเห็นได้ว่าการใช้งานจริงของ queryintentactivities อยู่ใน PackageManagerservice.java
รายการสาธารณะ <RolveInfo> queryIntentActive (เจตนาเจตนา, สตริง redvedType, int flag, int userId) {ถ้า (! "); componentNetName comp = intent.getComponent (); ถ้า (comp == null) {ถ้า (intent.getSelector ()! = null) {intent = intent.getSelect หรือ (); comp = intent.getComponent ();};}; } if (comp! = null) {// ความตั้งใจของ Explicit ได้รับรายการสุดท้ายที่สอดคล้องกันโดยตรง <SonvoInfo> list = new ArrayInfo> (1); null) {สุดท้าย ResolveInfo RI = ใหม่ ResolveInfo (); NULL) {// เจตนาโดยนัยส่งคืน mactivities.QueryIntent (เจตนา, ResolvedType, Flags, userId); ชื่อของเจตนาส่งคืน mactivities.quryintentForPackage (เจตนา, ResolvedType, Flags, pkg.activities, userid);จะเห็นได้ว่าการดำเนินการตามเจตนาที่ชัดเจนนั้นค่อนข้างง่าย ความตั้งใจโดยนัยเรียกว่าวิธีการ queryintent
รายการสาธารณะ <SonvoInfo> queryIntent (เจตนาเจตนา, สตริง redentType, int, int userId) {ถ้า (! susermanager.erid)) ส่งคืน null; )! = 0, userid);}ดำเนินการติดตามวิธีการ queryintent ของ intentresolver.java, ซอร์สโค้ดมีดังนี้:
รายการสาธารณะ <r> queryIntent (เจตนาเจตนา, String ResolvedType, Boolean default เพียงอย่างเดียว, intimeric) {String Scheme = Intent.getScheme (); รอบการจับคู่ F [] FirstTypecut = Null; slashpos = resolvedType.indexof ('/'); ถ้า (slashpos> 0) {สตริงสุดท้าย basetype = resrinetype = resring lvedtype.substring (0, slashpos); .length ()! = slashpos+2 || redentType.charat (slashpos+1)! = '*') {// ไม่ใช่การ์ดไวลด์ การแข่งขันประเภท ;} // ประเภท */ *ใด ๆ ที่ใช้เสมอ แต่เราต้องทำสิ่งนี้เท่านั้น // ถ้าประเภทนั้นไม่ใช่ almedy */ * ) = = null) {// ความตั้งใจที่ระบุประเภทใด ๆ (@literal*}/*) ; ;} // หากอินเตอร์ท์ไม่ได้ระบุข้อมูลใด ๆ - ประเภท MIME หรือ // URI - จากนั้นเราจะมองหาข้อมูล // ที่ว่างเปล่าที่ตรงกันเท่านั้น null) {FirstTypecut = mactiontofilter.get (intent.get.get ()); SecondTypecut! , ThirdTypecut, เข้ารอบสุดท้าย, userId);} ถ้า (schemecut! = null) {builtresolvelist (เจตนา, cate gories, debug, defaulting, resolvedtype, Scheme, schemecut, ผู้เข้ารอบสุดท้าย, ผู้ใช้);กระบวนการจับคู่แบบสอบถามที่เฉพาะเจาะจงนั้นเสร็จสมบูรณ์โดยฟังก์ชั่น BuildResolvelist ฉันไม่ได้โพสต์รหัสสำหรับการใช้งานการจับคู่ของแบบสอบถาม